bitkeeper revision 1.1159.212.25 (41f276d3ugY9cEgwC334t8sIzg3kiA)
authormwilli2@equilibrium.research <mwilli2@equilibrium.research>
Sat, 22 Jan 2005 15:52:51 +0000 (15:52 +0000)
committermwilli2@equilibrium.research <mwilli2@equilibrium.research>
Sat, 22 Jan 2005 15:52:51 +0000 (15:52 +0000)
USB virtualisation updated to 2.4.29.

22 files changed:
.rootkeys
linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/Makefile [deleted file]
linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/backend/Makefile [deleted file]
linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/backend/common.h [deleted file]
linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/backend/control.c [deleted file]
linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/backend/interface.c [deleted file]
linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/backend/main.c [deleted file]
linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/frontend/Makefile [deleted file]
linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/frontend/main.c [deleted file]
linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/frontend/xhci.h [deleted file]
linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/usbif.h [deleted file]
linux-2.4.28-xen-sparse/drivers/usb/hcd.c [deleted file]
linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/Makefile [new file with mode: 0644]
linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/backend/Makefile [new file with mode: 0644]
linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/backend/common.h [new file with mode: 0644]
linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/backend/control.c [new file with mode: 0644]
linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/backend/interface.c [new file with mode: 0644]
linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/backend/main.c [new file with mode: 0644]
linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/frontend/Makefile [new file with mode: 0644]
linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/frontend/main.c [new file with mode: 0644]
linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/frontend/xhci.h [new file with mode: 0644]
linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/usbif.h [new file with mode: 0644]

index d9c3d614e688e9d0e14c672161c3c0753bea5fb6..9348b79523e26c9b5da51a022090f08270bc3f0b 100644 (file)
--- a/.rootkeys
+++ b/.rootkeys
 3f815145vGYx1WY79voKkZB9yKwJKQ extras/mini-os/time.c
 3f815145xlKBAQmal9oces3G_Mvxqw extras/mini-os/traps.c
 4187ca95_eQN62ugV1zliQcfzXrHnw install.sh
-41ee5e8b_2rt-qHzbDXtIoBzOli0EA linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/Makefile
-41ee5e8bUhF4tH7OoJaVbUxdXqneVw linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/backend/Makefile
-41ee5e8bYDQkjRVKnFn5uFyy0KreCw linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/backend/common.h
-41ee5e8bt7xeBUJqG5XJS-ofukdsgA linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/backend/control.c
-41ee5e8bSs3BGC7yegM_ek2Tn0Ahvw linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/backend/interface.c
-41ee5e8bglvqKvZSY5uJ5JGQejEwyQ linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/backend/main.c
-41ee5e8bSPpxzhGO6TrY20TegW3cZg linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/frontend/Makefile
-41ee5e8ckZ9xVNvu9NHIZDK7JqApmQ linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/frontend/main.c
-41ee5e8ck9scpGirfqEZRARbGDyTXA linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/frontend/xhci.h
-41ee5e8c6mLxIx82KPsbpt_uts_vSA linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/usbif.h
-41ee5e8c__abdO50ZtQjPeSa5VN2dg linux-2.4.28-xen-sparse/drivers/usb/hcd.c
 3e5a4e6589G-U42lFKs43plskXoFxQ linux-2.4.29-xen-sparse/Makefile
 3e5a4e65IEPjnWPZ5w3TxS5scV8Ewg linux-2.4.29-xen-sparse/arch/xen/Makefile
 3e5a4e65n-KhsEAs-A4ULiStBp-r6w linux-2.4.29-xen-sparse/arch/xen/boot/Makefile
 4083dc16-Kd5y9psK_yk161sme5j5Q linux-2.4.29-xen-sparse/arch/xen/drivers/netif/Makefile
 4083dc16UmHXxS9g_UFVnkUpN-oP2Q linux-2.4.29-xen-sparse/arch/xen/drivers/netif/backend/Makefile
 405853f2wg7JXZJNltspMwOZJklxgw linux-2.4.29-xen-sparse/arch/xen/drivers/netif/frontend/Makefile
+41ee5e8b_2rt-qHzbDXtIoBzOli0EA linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/Makefile
+41ee5e8bUhF4tH7OoJaVbUxdXqneVw linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/backend/Makefile
+41ee5e8bYDQkjRVKnFn5uFyy0KreCw linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/backend/common.h
+41ee5e8bt7xeBUJqG5XJS-ofukdsgA linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/backend/control.c
+41ee5e8bSs3BGC7yegM_ek2Tn0Ahvw linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/backend/interface.c
+41ee5e8bglvqKvZSY5uJ5JGQejEwyQ linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/backend/main.c
+41ee5e8bSPpxzhGO6TrY20TegW3cZg linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/frontend/Makefile
+41ee5e8ckZ9xVNvu9NHIZDK7JqApmQ linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/frontend/main.c
+41ee5e8ck9scpGirfqEZRARbGDyTXA linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/frontend/xhci.h
+41ee5e8c6mLxIx82KPsbpt_uts_vSA linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/usbif.h
 3e5a4e65lWzkiPXsZdzPt2RNnJGG1g linux-2.4.29-xen-sparse/arch/xen/kernel/Makefile
 3e5a4e65_hqfuxtGG8IUy6wRM86Ecg linux-2.4.29-xen-sparse/arch/xen/kernel/entry.S
 3e5a4e65Hy_1iUvMTPsNqGNXd9uFpg linux-2.4.29-xen-sparse/arch/xen/kernel/head.S
diff --git a/linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/Makefile b/linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/Makefile
deleted file mode 100644 (file)
index 1b3eb41..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-
-O_TARGET := drv.o
-
-subdir-$(CONFIG_XEN_USB_FRONTEND) += frontend
-obj-$(CONFIG_XEN_USB_FRONTEND) += frontend/drv.o
-
-subdir-$(CONFIG_XEN_USB_BACKEND) += backend
-obj-$(CONFIG_XEN_USB_BACKEND)    += backend/drv.o
-
-include $(TOPDIR)/Rules.make
diff --git a/linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/backend/Makefile b/linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/backend/Makefile
deleted file mode 100644 (file)
index b5226dd..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-O_TARGET := drv.o
-obj-y := main.o interface.o control.o # vrh.o don't think I need this!
-include $(TOPDIR)/Rules.make
diff --git a/linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/backend/common.h b/linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/backend/common.h
deleted file mode 100644 (file)
index 550599a..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-
-#ifndef __USBIF__BACKEND__COMMON_H__
-#define __USBIF__BACKEND__COMMON_H__
-
-#include <linux/config.h>
-#include <linux/version.h>
-#include <linux/module.h>
-#include <linux/rbtree.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/blkdev.h>
-#include <asm/io.h>
-#include <asm/setup.h>
-#include <asm/pgalloc.h>
-#include <asm-xen/ctrl_if.h>
-#include <asm-xen/hypervisor.h>
-
-#include "../usbif.h"
-
-#if 0
-#define ASSERT(_p) \
-    if ( !(_p) ) { printk("Assertion '%s' failed, line %d, file %s", #_p , \
-    __LINE__, __FILE__); *(int*)0=0; }
-#define DPRINTK(_f, _a...) printk(KERN_ALERT "(file=%s, line=%d) " _f, \
-                           __FILE__ , __LINE__ , ## _a )
-#else
-#define ASSERT(_p) ((void)0)
-#define DPRINTK(_f, _a...) ((void)0)
-#endif
-
-typedef struct usbif_priv_st usbif_priv_t;
-
-struct usbif_priv_st {
-    /* Unique identifier for this interface. */
-    domid_t          domid;
-    unsigned int     handle;
-    /* Physical parameters of the comms window. */
-    unsigned long    shmem_frame;
-    unsigned int     evtchn;
-    int              irq;
-    /* Comms information. */
-    usbif_t      *usb_ring_base; /* ioremap()'ed ptr to shmem_frame. */
-    USBIF_RING_IDX     usb_req_cons;  /* Request consumer. */
-    USBIF_RING_IDX     usb_resp_prod; /* Private version of resp. producer. */
-    /* Private fields. */
-    enum { DISCONNECTED, DISCONNECTING, CONNECTED } status;
-    /*
-     * DISCONNECT response is deferred until pending requests are ack'ed.
-     * We therefore need to store the id from the original request.
-     */
-    u8                   disconnect_rspid;
-    usbif_priv_t *hash_next;
-    struct list_head     usbif_list;
-    spinlock_t           usb_ring_lock;
-    atomic_t             refcnt;
-    atomic_t             work_scheduled;
-
-    struct work_struct work;
-};
-
-void usbif_create(usbif_be_create_t *create);
-void usbif_destroy(usbif_be_destroy_t *destroy);
-void usbif_connect(usbif_be_connect_t *connect);
-int  usbif_disconnect(usbif_be_disconnect_t *disconnect, u8 rsp_id);
-void usbif_disconnect_complete(usbif_priv_t *up);
-
-void usbif_release_port(usbif_be_release_port_t *msg);
-int usbif_claim_port(usbif_be_claim_port_t *msg);
-void usbif_release_ports(usbif_priv_t *up);
-
-usbif_priv_t *usbif_find(domid_t domid);
-#define usbif_get(_b) (atomic_inc(&(_b)->refcnt))
-#define usbif_put(_b)                             \
-    do {                                          \
-        if ( atomic_dec_and_test(&(_b)->refcnt) ) \
-            usbif_disconnect_complete(_b);        \
-    } while (0)
-
-
-void usbif_interface_init(void);
-void usbif_ctrlif_init(void);
-
-void usbif_deschedule(usbif_priv_t *usbif);
-
-irqreturn_t usbif_be_int(int irq, void *dev_id, struct pt_regs *regs);
-
-#endif /* __USBIF__BACKEND__COMMON_H__ */
diff --git a/linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/backend/control.c b/linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/backend/control.c
deleted file mode 100644 (file)
index 899394a..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/******************************************************************************
- * arch/xen/drivers/usbif/backend/control.c
- * 
- * Routines for interfacing with the control plane.
- * 
- * Copyright (c) 2004, Keir Fraser
- */
-
-#include "common.h"
-
-static void usbif_ctrlif_rx(ctrl_msg_t *msg, unsigned long id)
-{
-    DPRINTK("Received usbif backend message, subtype=%d\n", msg->subtype);
-    
-    switch ( msg->subtype )
-    {
-    case CMSG_USBIF_BE_CREATE:
-        if ( msg->length != sizeof(usbif_be_create_t) )
-            goto parse_error;
-        usbif_create((usbif_be_create_t *)&msg->msg[0]);
-        break;        
-    case CMSG_USBIF_BE_DESTROY:
-        if ( msg->length != sizeof(usbif_be_destroy_t) )
-            goto parse_error;
-        usbif_destroy((usbif_be_destroy_t *)&msg->msg[0]);
-        break;        
-    case CMSG_USBIF_BE_CONNECT:
-        if ( msg->length != sizeof(usbif_be_connect_t) )
-            goto parse_error;
-        usbif_connect((usbif_be_connect_t *)&msg->msg[0]);
-        break;        
-    case CMSG_USBIF_BE_DISCONNECT:
-        if ( msg->length != sizeof(usbif_be_disconnect_t) )
-            goto parse_error;
-        if ( !usbif_disconnect((usbif_be_disconnect_t *)&msg->msg[0],msg->id) )
-            return; /* Sending the response is deferred until later. */
-        break;        
-    case CMSG_USBIF_BE_CLAIM_PORT:
-        if ( msg->length != sizeof(usbif_be_claim_port_t) )
-            goto parse_error;
-       usbif_claim_port((usbif_be_claim_port_t *)&msg->msg[0]);
-        break;
-    case CMSG_USBIF_BE_RELEASE_PORT:
-        if ( msg->length != sizeof(usbif_be_release_port_t) )
-            goto parse_error;
-        usbif_release_port((usbif_be_release_port_t *)&msg->msg[0]);
-        break;
-    default:
-        goto parse_error;
-    }
-
-    ctrl_if_send_response(msg);
-    return;
-
- parse_error:
-    DPRINTK("Parse error while reading message subtype %d, len %d\n",
-            msg->subtype, msg->length);
-    msg->length = 0;
-    ctrl_if_send_response(msg);
-}
-
-void usbif_ctrlif_init(void)
-{
-    ctrl_msg_t                       cmsg;
-    usbif_be_driver_status_changed_t st;
-
-    (void)ctrl_if_register_receiver(CMSG_USBIF_BE, usbif_ctrlif_rx, 
-                                    CALLBACK_IN_BLOCKING_CONTEXT);
-
-    /* Send a driver-UP notification to the domain controller. */
-    cmsg.type      = CMSG_USBIF_BE;
-    cmsg.subtype   = CMSG_USBIF_BE_DRIVER_STATUS_CHANGED;
-    cmsg.length    = sizeof(usbif_be_driver_status_changed_t);
-    st.status      = USBIF_DRIVER_STATUS_UP;
-    memcpy(cmsg.msg, &st, sizeof(st));
-    ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
-}
diff --git a/linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/backend/interface.c b/linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/backend/interface.c
deleted file mode 100644 (file)
index 7b49ae5..0000000
+++ /dev/null
@@ -1,248 +0,0 @@
-/******************************************************************************
- * arch/xen/drivers/usbif/backend/interface.c
- * 
- * USB device interface management.
- * 
- * by Mark Williamson, Copyright (c) 2004
- */
-
-
-/******************************************************************************
- * arch/xen/drivers/blkif/backend/interface.c
- * 
- * Block-device interface management.
- * 
- * Copyright (c) 2004, Keir Fraser
- */
-
-#include "common.h"
-
-#define USBIF_HASHSZ 1024
-#define USBIF_HASH(_d) (((int)(_d))&(USBIF_HASHSZ-1))
-
-static kmem_cache_t      *usbif_priv_cachep;
-static usbif_priv_t      *usbif_priv_hash[USBIF_HASHSZ];
-
-usbif_priv_t *usbif_find(domid_t domid)
-{
-    usbif_priv_t *up = usbif_priv_hash[USBIF_HASH(domid)];
-    while ( (up != NULL ) && ( up->domid != domid ) )
-        up = up->hash_next;
-    return up;
-}
-
-static void __usbif_disconnect_complete(void *arg)
-{
-    usbif_priv_t         *usbif = (usbif_priv_t *)arg;
-    ctrl_msg_t            cmsg;
-    usbif_be_disconnect_t disc;
-
-    /*
-     * These can't be done in usbif_disconnect() because at that point there
-     * may be outstanding requests at the device whose asynchronous responses
-     * must still be notified to the remote driver.
-     */
-    unbind_evtchn_from_irq(usbif->evtchn);
-    vfree(usbif->usb_ring_base);
-
-    /* Construct the deferred response message. */
-    cmsg.type         = CMSG_USBIF_BE;
-    cmsg.subtype      = CMSG_USBIF_BE_DISCONNECT;
-    cmsg.id           = usbif->disconnect_rspid;
-    cmsg.length       = sizeof(usbif_be_disconnect_t);
-    disc.domid        = usbif->domid;
-    disc.status       = USBIF_BE_STATUS_OKAY;
-    memcpy(cmsg.msg, &disc, sizeof(disc));
-
-    /*
-     * Make sure message is constructed /before/ status change, because
-     * after the status change the 'usbif' structure could be deallocated at
-     * any time. Also make sure we send the response /after/ status change,
-     * as otherwise a subsequent CONNECT request could spuriously fail if
-     * another CPU doesn't see the status change yet.
-     */
-    mb();
-    if ( usbif->status != DISCONNECTING )
-        BUG();
-    usbif->status = DISCONNECTED;
-    mb();
-
-    /* Send the successful response. */
-    ctrl_if_send_response(&cmsg);
-}
-
-void usbif_disconnect_complete(usbif_priv_t *up)
-{
-    INIT_WORK(&up->work, __usbif_disconnect_complete, (void *)up);
-    schedule_work(&up->work);
-}
-
-void usbif_create(usbif_be_create_t *create)
-{
-    domid_t       domid  = create->domid;
-    usbif_priv_t **pup, *up;
-
-    if ( (up = kmem_cache_alloc(usbif_priv_cachep, GFP_KERNEL)) == NULL )
-    {
-        DPRINTK("Could not create usbif: out of memory\n");
-        create->status = USBIF_BE_STATUS_OUT_OF_MEMORY;
-        return;
-    }
-
-    memset(up, 0, sizeof(*up));
-    up->domid  = domid;
-    up->status = DISCONNECTED;
-    spin_lock_init(&up->usb_ring_lock);
-    atomic_set(&up->refcnt, 0);
-
-    pup = &usbif_priv_hash[USBIF_HASH(domid)];
-    while ( *pup != NULL )
-    {
-        if ( (*pup)->domid == domid )
-        {
-            create->status = USBIF_BE_STATUS_INTERFACE_EXISTS;
-            kmem_cache_free(usbif_priv_cachep, up);
-            return;
-        }
-        pup = &(*pup)->hash_next;
-    }
-
-    up->hash_next = *pup;
-    *pup = up;
-
-    create->status = USBIF_BE_STATUS_OKAY;
-}
-
-void usbif_destroy(usbif_be_destroy_t *destroy)
-{
-    domid_t       domid  = destroy->domid;
-    usbif_priv_t  **pup, *up;
-
-    pup = &usbif_priv_hash[USBIF_HASH(domid)];
-    while ( (up = *pup) != NULL )
-    {
-        if ( up->domid == domid )
-        {
-            if ( up->status != DISCONNECTED )
-                goto still_connected;
-            goto destroy;
-        }
-        pup = &up->hash_next;
-    }
-
-    destroy->status = USBIF_BE_STATUS_INTERFACE_NOT_FOUND;
-    return;
-
- still_connected:
-    destroy->status = USBIF_BE_STATUS_INTERFACE_CONNECTED;
-    return;
-
- destroy:
-    *pup = up->hash_next;
-    usbif_release_ports(up);
-    kmem_cache_free(usbif_priv_cachep, up);
-    destroy->status = USBIF_BE_STATUS_OKAY;
-}
-
-void usbif_connect(usbif_be_connect_t *connect)
-{
-    domid_t       domid  = connect->domid;
-    unsigned int  evtchn = connect->evtchn;
-    unsigned long shmem_frame = connect->shmem_frame;
-    struct vm_struct *vma;
-    pgprot_t      prot;
-    int           error;
-    usbif_priv_t *up;
-
-    up = usbif_find(domid);
-    if ( unlikely(up == NULL) )
-    {
-        DPRINTK("usbif_connect attempted for non-existent usbif (%u)\n", 
-                connect->domid); 
-        connect->status = USBIF_BE_STATUS_INTERFACE_NOT_FOUND;
-        return;
-    }
-
-    if ( (vma = get_vm_area(PAGE_SIZE, VM_IOREMAP)) == NULL )
-    {
-        connect->status = USBIF_BE_STATUS_OUT_OF_MEMORY;
-        return;
-    }
-
-    prot = __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED);
-    error = direct_remap_area_pages(&init_mm, VMALLOC_VMADDR(vma->addr),
-                                    shmem_frame<<PAGE_SHIFT, PAGE_SIZE,
-                                    prot, domid);
-    if ( error != 0 )
-    {
-        if ( error == -ENOMEM )
-            connect->status = USBIF_BE_STATUS_OUT_OF_MEMORY;
-        else if ( error == -EFAULT )
-            connect->status = USBIF_BE_STATUS_MAPPING_ERROR;
-        else
-            connect->status = USBIF_BE_STATUS_ERROR;
-        vfree(vma->addr);
-        return;
-    }
-
-    if ( up->status != DISCONNECTED )
-    {
-        connect->status = USBIF_BE_STATUS_INTERFACE_CONNECTED;
-        vfree(vma->addr);
-        return;
-    }
-
-    up->evtchn        = evtchn;
-    up->irq           = bind_evtchn_to_irq(evtchn);
-    up->shmem_frame   = shmem_frame;
-    up->usb_ring_base = (usbif_t *)vma->addr;
-    up->status        = CONNECTED;
-    usbif_get(up);
-
-    request_irq(up->irq, usbif_be_int, 0, "usbif-backend", up);
-
-    connect->status = USBIF_BE_STATUS_OKAY;
-}
-
-/* Remove URBs for this interface before destroying it. */
-void usbif_deschedule(usbif_priv_t *up)
-{
-    remove_from_usbif_list(up);
-}
-
-int usbif_disconnect(usbif_be_disconnect_t *disconnect, u8 rsp_id)
-{
-    domid_t       domid  = disconnect->domid;
-    usbif_priv_t *up;
-
-    up = usbif_find(domid);
-    if ( unlikely(up == NULL) )
-    {
-        DPRINTK("usbif_disconnect attempted for non-existent usbif"
-                " (%u)\n", disconnect->domid); 
-        disconnect->status = USBIF_BE_STATUS_INTERFACE_NOT_FOUND;
-        return 1; /* Caller will send response error message. */
-    }
-
-    if ( up->status == CONNECTED )
-    {
-        up->status = DISCONNECTING;
-        up->disconnect_rspid = rsp_id;
-        wmb(); /* Let other CPUs see the status change. */
-        free_irq(up->irq, up);
-       usbif_deschedule(up);
-        usbif_put(up);
-        return 0; /* Caller should not send response message. */
-    }
-
-    disconnect->status = USBIF_BE_STATUS_OKAY;
-    return 1;
-}
-
-void __init usbif_interface_init(void)
-{
-    usbif_priv_cachep = kmem_cache_create("usbif_priv_cache",
-                                         sizeof(usbif_priv_t), 
-                                         0, 0, NULL, NULL);
-    memset(usbif_priv_hash, 0, sizeof(usbif_priv_hash));
-}
diff --git a/linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/backend/main.c b/linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/backend/main.c
deleted file mode 100644 (file)
index 51ce5bd..0000000
+++ /dev/null
@@ -1,1011 +0,0 @@
-/******************************************************************************
- * arch/xen/drivers/usbif/backend/main.c
- * 
- * Backend for the Xen virtual USB driver - provides an abstraction of a
- * USB host controller to the corresponding frontend driver.
- *
- * by Mark Williamson, Copyright (c) 2004 Intel Research Cambridge
- *
- * Based on arch/xen/drivers/blkif/backend/main.c
- * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
- */
-
-#include "common.h"
-
-
-#include <linux/list.h>
-#include <linux/usb.h>
-#include <linux/spinlock.h>
-#include <linux/module.h>
-#include <linux/tqueue.h>
-
-/*
- * This is rather arbitrary.
- */
-#define MAX_PENDING_REQS 4
-#define BATCH_PER_DOMAIN 1
-
-static unsigned long mmap_vstart;
-
-/* Needs to be sufficiently large that we can map the (large) buffers
- * the USB mass storage driver wants. */
-#define MMAP_PAGES_PER_REQUEST \
-    (128)
-#define MMAP_PAGES             \
-    (MAX_PENDING_REQS * MMAP_PAGES_PER_REQUEST)
-
-#define MMAP_VADDR(_req,_seg)                        \
-    (mmap_vstart +                                   \
-     ((_req) * MMAP_PAGES_PER_REQUEST * PAGE_SIZE) + \
-     ((_seg) * PAGE_SIZE))
-
-#define MIN(x,y) ( ( x < y ) ? x : y )
-
-static spinlock_t owned_ports_lock;
-LIST_HEAD(owned_ports);
-
-/* A list of these structures is used to track ownership of physical USB
- * ports. */
-typedef struct 
-{
-    usbif_priv_t     *usbif_priv;
-    char             path[16];
-    int               guest_port;
-    int enabled;
-    struct list_head  list;
-    unsigned long guest_address; /* The USB device address that has been
-                                  * assigned by the guest. */
-    int               dev_present; /* Is there a device present? */
-    struct usb_device * dev;
-    unsigned long ifaces;  /* What interfaces are present on this device? */
-} owned_port_t;
-
-
-/*
- * Each outstanding request that we've passed to the lower device layers has a
- * 'pending_req' allocated to it.  The request is complete, the specified
- * domain has a response queued for it, with the saved 'id' passed back.
- */
-typedef struct {
-    usbif_priv_t       *usbif_priv;
-    usbif_iso_t        *iso_sched;
-    unsigned long      id;
-    int                nr_pages;
-    unsigned short     operation;
-    int                status;
-} pending_req_t;
-
-/*
- * We can't allocate pending_req's in order, since they may complete out of 
- * order. We therefore maintain an allocation ring. This ring also indicates 
- * when enough work has been passed down -- at that point the allocation ring 
- * will be empty.
- */
-static pending_req_t pending_reqs[MAX_PENDING_REQS];
-static unsigned char pending_ring[MAX_PENDING_REQS];
-static spinlock_t pend_prod_lock = SPIN_LOCK_UNLOCKED;
-
-/* NB. We use a different index type to differentiate from shared blk rings. */
-typedef unsigned int PEND_RING_IDX;
-#define MASK_PEND_IDX(_i) ((_i)&(MAX_PENDING_REQS-1))
-static PEND_RING_IDX pending_prod, pending_cons;
-#define NR_PENDING_REQS (MAX_PENDING_REQS - pending_prod + pending_cons)
-
-static int do_usb_io_op(usbif_priv_t *usbif, int max_to_do);
-static void make_response(usbif_priv_t *usbif, unsigned long id, 
-                          unsigned short op, int st, int inband,
-                         unsigned long actual_length);
-static void dispatch_usb_probe(usbif_priv_t *up, unsigned long id, unsigned long port);
-static void dispatch_usb_io(usbif_priv_t *up, usbif_request_t *req);    
-static void dispatch_usb_reset(usbif_priv_t *up, unsigned long portid);
-static owned_port_t *usbif_find_port(char *);
-
-
-void dump_port(owned_port_t *p)
-{
-    printk("owned_port_t @ %p\n", p);
-    printk("  usbif_priv @ %p\n", p->usbif_priv);
-    printk("  path: %s\n", p->path);
-    printk("  guest_port: %d\n", p->guest_port);
-    printk("  guest_address: %ld\n", p->guest_address);
-    printk("  dev_present: %d\n", p->dev_present);
-    printk("  dev @ %p\n", p->dev);
-    printk("  ifaces: 0x%lx\n", p->ifaces);
-}
-
-
-
-static void fast_flush_area(int idx, int nr_pages)
-{
-    multicall_entry_t mcl[MMAP_PAGES_PER_REQUEST];
-    int               i;
-
-    for ( i = 0; i < nr_pages; i++ )
-    {
-        mcl[i].op = __HYPERVISOR_update_va_mapping;
-        mcl[i].args[0] = MMAP_VADDR(idx, i) >> PAGE_SHIFT;
-        mcl[i].args[1] = 0;
-        mcl[i].args[2] = 0;
-    }
-
-    mcl[nr_pages-1].args[2] = UVMF_FLUSH_TLB;
-    if ( unlikely(HYPERVISOR_multicall(mcl, nr_pages) != 0) )
-        BUG();
-}
-
-
-/******************************************************************
- * USB INTERFACE SCHEDULER LIST MAINTENANCE
- */
-
-static struct list_head usbio_schedule_list;
-static spinlock_t usbio_schedule_list_lock;
-
-static int __on_usbif_list(usbif_priv_t *up)
-{
-    return up->usbif_list.next != NULL;
-}
-
-void remove_from_usbif_list(usbif_priv_t *up)
-{
-    unsigned long flags;
-    if ( !__on_usbif_list(up) ) return;
-    spin_lock_irqsave(&usbio_schedule_list_lock, flags);
-    if ( __on_usbif_list(up) )
-    {
-        list_del(&up->usbif_list);
-        up->usbif_list.next = NULL;
-        usbif_put(up);
-    }
-    spin_unlock_irqrestore(&usbio_schedule_list_lock, flags);
-}
-
-static void add_to_usbif_list_tail(usbif_priv_t *up)
-{
-    unsigned long flags;
-    if ( __on_usbif_list(up) ) return;
-    spin_lock_irqsave(&usbio_schedule_list_lock, flags);
-    if ( !__on_usbif_list(up) && (up->status == CONNECTED) )
-    {
-        list_add_tail(&up->usbif_list, &usbio_schedule_list);
-        usbif_get(up);
-    }
-    spin_unlock_irqrestore(&usbio_schedule_list_lock, flags);
-}
-
-
-/******************************************************************
- * COMPLETION CALLBACK -- Called as urb->complete()
- */
-
-static void maybe_trigger_usbio_schedule(void);
-
-static void __end_usb_io_op(struct urb *purb)
-{
-    unsigned long flags;
-    pending_req_t *pending_req;
-    int pending_idx;
-
-    pending_req = purb->context;
-
-/*     printk("Completed for id = %p to 0x%lx - 0x%lx\n", pending_req->id, */
-/*            virt_to_machine(purb->transfer_buffer), */
-/*            virt_to_machine(purb->transfer_buffer) */
-/*            + pending_req->nr_pages * PAGE_SIZE); */
-
-    pending_idx = pending_req - pending_reqs;
-
-    ASSERT(purb->actual_length <= purb->transfer_buffer_length);
-    ASSERT(purb->actual_length <= pending_req->nr_pages * PAGE_SIZE);
-    
-    /* An error fails the entire request. */
-    if ( purb->status )
-    {
-        printk("URB @ %p failed. Status %d\n", purb, purb->status);
-    }
-
-    if ( usb_pipetype(purb->pipe) == 0 )
-    {
-        int i;
-        usbif_iso_t *sched = (usbif_iso_t *)MMAP_VADDR(pending_idx, pending_req->nr_pages - 1);
-
-        ASSERT(sched == pending_req->sched);
-
-       //      printk("writing back schedule at %p\n", sched);
-
-        /* If we're dealing with an iso pipe, we need to copy back the schedule. */
-        for ( i = 0; i < purb->number_of_packets; i++ )
-        {
-            sched[i].length = purb->iso_frame_desc[i].actual_length;
-            ASSERT(sched[i].buffer_offset ==
-                   purb->iso_frame_desc[i].offset);
-            sched[i].status = purb->iso_frame_desc[i].status;
-        }
-    }
-    
-    //    printk("Flushing %d pages\n", pending_req->nr_pages);
-    fast_flush_area(pending_req - pending_reqs, pending_req->nr_pages);
-
-    kfree(purb->setup_packet);
-
-    spin_lock_irqsave(&pending_req->usbif_priv->usb_ring_lock, flags);
-    make_response(pending_req->usbif_priv, pending_req->id,
-                 pending_req->operation, pending_req->status, 0, purb->actual_length);
-    spin_unlock_irqrestore(&pending_req->usbif_priv->usb_ring_lock, flags);
-    usbif_put(pending_req->usbif_priv);
-
-    usb_free_urb(purb);
-
-    /* Free the pending request. */
-    spin_lock_irqsave(&pend_prod_lock, flags);
-    pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx;
-    spin_unlock_irqrestore(&pend_prod_lock, flags);
-
-    rmb();
-
-    /* Check for anything still waiting in the rings, having freed a request... */
-    maybe_trigger_usbio_schedule();
-}
-
-/******************************************************************
- * SCHEDULER FUNCTIONS
- */
-
-static DECLARE_WAIT_QUEUE_HEAD(usbio_schedule_wait);
-
-static int usbio_schedule(void *arg)
-{
-    DECLARE_WAITQUEUE(wq, current);
-
-    usbif_priv_t          *up;
-    struct list_head *ent;
-
-    daemonize();
-
-    for ( ; ; )
-    {
-        /* Wait for work to do. */
-        add_wait_queue(&usbio_schedule_wait, &wq);
-        set_current_state(TASK_INTERRUPTIBLE);
-        if ( (NR_PENDING_REQS == MAX_PENDING_REQS) || 
-             list_empty(&usbio_schedule_list) )
-            schedule();
-        __set_current_state(TASK_RUNNING);
-        remove_wait_queue(&usbio_schedule_wait, &wq);
-
-        /* Queue up a batch of requests. */
-        while ( (NR_PENDING_REQS < MAX_PENDING_REQS) &&
-                !list_empty(&usbio_schedule_list) )
-        {
-            ent = usbio_schedule_list.next;
-            up = list_entry(ent, usbif_priv_t, usbif_list);
-            usbif_get(up);
-            remove_from_usbif_list(up);
-            if ( do_usb_io_op(up, BATCH_PER_DOMAIN) )
-                add_to_usbif_list_tail(up);
-            usbif_put(up);
-        }
-    }
-}
-
-static void maybe_trigger_usbio_schedule(void)
-{
-    /*
-     * Needed so that two processes, who together make the following predicate
-     * true, don't both read stale values and evaluate the predicate
-     * incorrectly. Incredibly unlikely to stall the scheduler on x86, but...
-     */
-    smp_mb();
-
-    if ( !list_empty(&usbio_schedule_list) )
-        wake_up(&usbio_schedule_wait);
-}
-
-
-/******************************************************************************
- * NOTIFICATION FROM GUEST OS.
- */
-
-irqreturn_t usbif_be_int(int irq, void *dev_id, struct pt_regs *regs)
-{
-    usbif_priv_t *up = dev_id;
-
-    smp_mb();
-
-    add_to_usbif_list_tail(up); 
-
-    /* Will in fact /always/ trigger an io schedule in this case. */
-    maybe_trigger_usbio_schedule();
-
-    return IRQ_HANDLED;
-}
-
-
-
-/******************************************************************
- * DOWNWARD CALLS -- These interface with the usb-device layer proper.
- */
-
-static int do_usb_io_op(usbif_priv_t *up, int max_to_do)
-{
-    usbif_t *usb_ring = up->usb_ring_base;
-    usbif_request_t *req;
-    USBIF_RING_IDX i, rp;
-    int more_to_do = 0;
-    unsigned long flags;
-
-    spin_lock_irqsave(&up->usb_ring_lock, flags);
-
-    rp = usb_ring->req_prod;
-    rmb(); /* Ensure we see queued requests up to 'rp'. */
-    
-    /* Take items off the comms ring, taking care not to overflow. */
-    for ( i = up->usb_req_cons; 
-          (i != rp) && ((i-up->usb_resp_prod) != USBIF_RING_SIZE);
-          i++ )
-    {
-        if ( (max_to_do-- == 0) || (NR_PENDING_REQS == MAX_PENDING_REQS) )
-        {
-            more_to_do = 1;
-            break;
-        }
-
-        req = &usb_ring->ring[MASK_USBIF_IDX(i)].req;
-        
-        switch ( req->operation )
-        {
-        case USBIF_OP_PROBE:
-            dispatch_usb_probe(up, req->id, req->port);
-            break;
-
-        case USBIF_OP_IO:
-         /* Assemble an appropriate URB. */
-         dispatch_usb_io(up, req);
-          break;
-
-       case USBIF_OP_RESET:
-         dispatch_usb_reset(up, req->port);
-          break;
-
-        default:
-            DPRINTK("error: unknown USB io operation [%d]\n",
-                    req->operation);
-            make_response(up, req->id, req->operation, -EINVAL, 0, 0);
-            break;
-        }
-    }
-
-    up->usb_req_cons = i;
-
-    spin_unlock_irqrestore(&up->usb_ring_lock, flags);
-
-    return more_to_do;
-}
-
-static owned_port_t *find_guest_port(usbif_priv_t *up, int port)
-{
-    unsigned long flags;
-    struct list_head *l;
-
-    spin_lock_irqsave(&owned_ports_lock, flags);
-    list_for_each(l, &owned_ports)
-    {
-        owned_port_t *p = list_entry(l, owned_port_t, list);
-        if(p->usbif_priv == up && p->guest_port == port)
-        {
-            spin_unlock_irqrestore(&owned_ports_lock, flags);
-            return p;
-        }
-    }
-    spin_unlock_irqrestore(&owned_ports_lock, flags);
-
-    return NULL;
-}
-
-static void dispatch_usb_reset(usbif_priv_t *up, unsigned long portid)
-{
-    owned_port_t *port = find_guest_port(up, portid);
-    int ret = 0;
-
-
-    /* Allowing the guest to actually reset the device causes more problems
-     * than it's worth.  We just fake it out in software but we will do a real
-     * reset when the interface is destroyed. */
-
-#if 0
-    printk("Reset port %d\n", portid);
-
-    dump_port(port);
-#endif
-
-    port->guest_address = 0;
-    /* If there's an attached device then the port is now enabled. */
-    if ( port->dev_present )
-        port->enabled = 1;
-    else
-        port->enabled = 0;
-
-    make_response(up, 0, USBIF_OP_RESET, ret, 0, 0);
-}
-
-static void dispatch_usb_probe(usbif_priv_t *up, unsigned long id, unsigned long portid)
-{
-    owned_port_t *port = find_guest_port(up, portid);
-    int ret;
-    if ( port != NULL )
-        ret = port->dev_present;
-    else
-    {
-        ret = -EINVAL;
-        printk("dispatch_usb_probe(): invalid port probe request (port %ld)\n",
-              portid);
-    }
-
-    /* Probe result is sent back in-band.  Probes don't have an associated id
-     * right now... */
-    make_response(up, id, USBIF_OP_PROBE, ret, portid, 0);
-}
-
-owned_port_t *find_port_for_request(usbif_priv_t *up, usbif_request_t *req);
-
-static void dump_request(usbif_request_t *req)
-{    
-    printk("id = 0x%lx\n", req->id);
-    
-       printk("devnum %d\n", req->devnum);
-       printk("endpoint 0x%x\n", req->endpoint);
-       printk("direction %d\n", req->direction);
-       printk("speed %d\n", req->speed);
-        printk("pipe_type 0x%x\n", req->pipe_type);
-        printk("transfer_buffer 0x%lx\n", req->transfer_buffer);
-        printk("length 0x%lx\n", req->length);
-        printk("transfer_flags 0x%lx\n", req->transfer_flags);
-        printk("setup = { 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n",
-               req->setup[0], req->setup[1], req->setup[2], req->setup[3],
-               req->setup[4], req->setup[5], req->setup[6], req->setup[7]);
-        printk("iso_schedule = 0x%lx\n", req->iso_schedule);
-        printk("num_iso %ld\n", req->num_iso);
-}
-
-void dump_urb(struct urb *urb)
-{
-    printk("dumping urb @ %p\n", urb);
-
-#define DUMP_URB_FIELD(name, format) printk("  " # name " " format "\n", urb-> name)
-    
-    DUMP_URB_FIELD(pipe, "0x%x");
-    DUMP_URB_FIELD(status, "%d");
-    DUMP_URB_FIELD(transfer_flags, "0x%x");    
-    DUMP_URB_FIELD(transfer_buffer, "%p");
-    DUMP_URB_FIELD(transfer_buffer_length, "%d");
-    DUMP_URB_FIELD(actual_length, "%d");
-}
-
-
-static void dispatch_usb_io(usbif_priv_t *up, usbif_request_t *req)
-{
-    unsigned long buffer_mach;
-    int i = 0, offset = 0,
-        pending_idx = pending_ring[MASK_PEND_IDX(pending_cons)];
-    pending_req_t *pending_req;
-    unsigned long  remap_prot;
-    multicall_entry_t mcl[MMAP_PAGES_PER_REQUEST];
-    struct urb *purb = NULL;
-    owned_port_t *port;
-    unsigned char *setup;    
-
-//    dump_request(req);
-
-    if ( NR_PENDING_REQS == MAX_PENDING_REQS )
-    {
-        printk("usbback: Max requests already queued.  Now giving up!\n");
-        
-        return;
-    }
-
-    port = find_port_for_request(up, req);
-
-    if(port == NULL)
-    {
-       printk("No such device! (%d)\n", req->devnum);
-       dump_request(req);
-
-        make_response(up, req->id, req->operation, -ENODEV, 0, 0);
-       return;
-    }
-
-    setup = kmalloc(8, GFP_ATOMIC | GFP_NOIO);
-
-    if ( setup == NULL )
-        goto no_mem;
-   
-    /* Copy request out for safety. */
-    memcpy(setup, req->setup, 8);
-
-    if( setup[0] == 0x0 && setup[1] == 0x5)
-    {
-        /* To virtualise the USB address space, we need to intercept
-         * set_address messages and emulate.  From the USB specification:
-         * bmRequestType = 0x0;
-         * Brequest = SET_ADDRESS (i.e. 0x5)
-         * wValue = device address
-         * wIndex = 0
-         * wLength = 0
-         * data = None
-         */
-        /* Store into the guest transfer buffer using cpu_to_le16 */
-        port->guest_address = le16_to_cpu(*(u16 *)(setup + 2));
-        /* Make a successful response.  That was easy! */
-
-        make_response(up, req->id, req->operation, 0, 0, 0);
-
-       kfree(setup);
-        return;
-    }
-    else if ( setup[0] == 0x0 && setup[1] == 0x9 )
-    {
-        /* The host kernel needs to know what device configuration is in use
-         * because various error checks get confused otherwise.  We just do
-         * configuration settings here, under controlled conditions.
-         */
-        usb_set_configuration(port->dev, setup[2]);
-
-        make_response(up, req->id, req->operation, 0, 0, 0);
-
-        kfree(setup);
-        return;
-    }
-
-    else if ( setup[0] == 0x1 && setup[1] == 0xB )
-    {
-        /* The host kernel needs to know what device interface is in use
-         * because various error checks get confused otherwise.  We just do
-         * configuration settings here, under controlled conditions.
-         */
-        usb_set_interface(port->dev, (setup[4] | setup[5] << 8),
-                          (setup[2] | setup[3] << 8) );
-
-        make_response(up, req->id, req->operation, 0, 0, 0);
-
-        kfree(setup);
-        return;
-    }
-
-    if ( ( req->transfer_buffer - (req->transfer_buffer & PAGE_MASK)
-          + req->length )
-        > MMAP_PAGES_PER_REQUEST * PAGE_SIZE )
-    {
-        printk("usbback: request of %d bytes too large, failing it\n", req->length);
-        make_response(up, req->id, req->operation, -EINVAL, 0, 0);
-        kfree(setup);
-        return;
-    }
-    
-    buffer_mach = req->transfer_buffer;
-
-    if( buffer_mach == 0 )
-       goto no_remap;
-
-    ASSERT((req->length >> PAGE_SHIFT) <= MMAP_PAGES_PER_REQUEST);
-    ASSERT(buffer_mach);
-
-    /* Always map writeable for now. */
-    remap_prot = _PAGE_PRESENT|_PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_RW;
-
-    for ( i = 0, offset = 0; offset < req->length;
-          i++, offset += PAGE_SIZE )
-    {
-      //        printk("length = %d, offset = %d, looping!\n", req->length, offset);
-        
-       mcl[i].op = __HYPERVISOR_update_va_mapping_otherdomain;
-       mcl[i].args[0] = MMAP_VADDR(pending_idx, i) >> PAGE_SHIFT;
-        mcl[i].args[1] = ((buffer_mach & PAGE_MASK) + offset) | remap_prot;
-        mcl[i].args[2] = 0;
-        mcl[i].args[3] = up->domid;
-        
-        phys_to_machine_mapping[__pa(MMAP_VADDR(pending_idx, i))>>PAGE_SHIFT] =
-            FOREIGN_FRAME((buffer_mach + offset) >> PAGE_SHIFT);
-       //      printk("i = %d\n", i);
-
-        ASSERT(virt_to_machine(MMAP_VADDR(pending_idx, i))
-               == buffer_mach + i << PAGE_SHIFT);
-    }
-
-    if ( req->pipe_type == 0 && req->num_iso > 0 ) /* Maybe schedule ISO... */
-    {
-      //      printk("for iso, i = %d\n", i);
-        /* Map in ISO schedule, if necessary. */
-        mcl[i].op = __HYPERVISOR_update_va_mapping_otherdomain;
-        mcl[i].args[0] = MMAP_VADDR(pending_idx, i) >> PAGE_SHIFT;
-        mcl[i].args[1] = (req->iso_schedule & PAGE_MASK) | remap_prot;
-        mcl[i].args[2] = 0;
-        mcl[i].args[3] = up->domid;
-
-        phys_to_machine_mapping[__pa(MMAP_VADDR(pending_idx, i))>>PAGE_SHIFT] =
-            FOREIGN_FRAME(req->iso_schedule >> PAGE_SHIFT);
-    
-        //    printk("Mapped iso at %p\n", MMAP_VADDR(pending_idx, i));
-        i++;
-    }
-
-    //    printk("Well we got this far!\n");
-
-    if ( unlikely(HYPERVISOR_multicall(mcl, i) != 0) )
-        BUG();
-    
-    {
-        int j;
-        for ( j = 0; j < i; j++ )
-        {
-            if ( unlikely(mcl[j].args[5] != 0) )
-            {
-                printk("invalid buffer %d -- could not remap it\n", j);
-                fast_flush_area(pending_idx, i);
-               printk("sending invalid descriptor\n");
-                goto bad_descriptor;
-            }
-       }
-    }
-    
- no_remap:
-
-    ASSERT(i <= MMAP_PAGES_PER_REQUEST);
-    ASSERT(i * PAGE_SIZE >= req->length);
-
-    /* We have to do this because some things might complete out of order. */
-    pending_req = &pending_reqs[pending_idx];
-    pending_req->usbif_priv= up;
-    pending_req->id        = req->id;
-    pending_req->operation = req->operation;
-    pending_req->nr_pages  = i;
-
-
-
-    pending_cons++;
-
-    usbif_get(up);
-    
-    /* Fill out an actual request for the USB layer. */
-    purb = usb_alloc_urb(req->num_iso);
-
-    if ( purb == NULL )
-        goto no_mem;
-
-    purb->dev = port->dev;
-    purb->context = pending_req;
-    purb->transfer_buffer = (void *)MMAP_VADDR(pending_idx, 0) + (buffer_mach & ~PAGE_MASK);
-    if(buffer_mach == 0)
-      purb->transfer_buffer = NULL;
-    purb->complete = __end_usb_io_op;
-    purb->transfer_buffer_length = req->length;
-    purb->transfer_flags = req->transfer_flags;
-
-/*     if ( req->transfer_flags != 0 ) */
-/*       dump_request(req); */
-
-    purb->pipe = 0;
-    purb->pipe |= req->direction << 7;
-    purb->pipe |= port->dev->devnum << 8;
-    purb->pipe |= req->speed << 26;
-    purb->pipe |= req->pipe_type << 30;
-    purb->pipe |= req->endpoint << 15;
-
-    purb->number_of_packets = req->num_iso;
-
-    /* Make sure there's always some kind of timeout. */
-    purb->timeout = ( req->timeout > 0 ) ?  (req->timeout * HZ) / 1000
-                    :  1000;
-
-    purb->setup_packet = setup;
-
-    if ( req->pipe_type == 0 ) /* ISO */
-    {
-        int j;
-        usbif_iso_t *iso_sched = (usbif_iso_t *)MMAP_VADDR(pending_idx, i - 1);
-
-       //      printk("Reading iso sched at %p\n", iso_sched);
-
-        /* If we're dealing with an iso pipe, we need to copy in a schedule. */
-        for ( j = 0; j < req->num_iso; j++ )
-        {
-            purb->iso_frame_desc[j].length = iso_sched[j].length;
-            purb->iso_frame_desc[j].offset = iso_sched[j].buffer_offset;
-            iso_sched[j].status = 0;
-        }
-        pending_req->iso_sched = iso_sched;
-    }
-
-    {
-      int ret;
-      ret = usb_submit_urb(purb);
-
-      //      dump_urb(purb);
-
-      if ( ret != 0 )
-          goto bad_descriptor; /* XXX free pending here! */
-    }
-    
-    return;
-
- bad_descriptor:
-    kfree ( setup );
-    if ( purb != NULL )
-        usb_free_urb(purb);
-    make_response(up, req->id, req->operation, -EINVAL, 0, 0);
-    return;
-    
- no_mem:
-    if ( setup != NULL )
-        kfree(setup);
-    make_response(up, req->id, req->operation, -ENOMEM, 0, 0);
-    return;
-} 
-
-
-
-/******************************************************************
- * MISCELLANEOUS SETUP / TEARDOWN / DEBUGGING
- */
-
-
-static void make_response(usbif_priv_t *up, unsigned long id,
-                          unsigned short op, int st, int inband,
-                         unsigned long length)
-{
-    usbif_response_t *resp;
-    unsigned long     flags;
-
-#if 0
-    printk("usbback: Sending response:\n");
-    printk("         id = 0x%x\n", id);
-    printk("         op = %d\n", op);
-    printk("         status = %d\n", st);
-    printk("         data = %d\n", inband);
-    printk("         length = %d\n", length);
-#endif
-
-    /* Place on the response ring for the relevant domain. */ 
-    spin_lock_irqsave(&up->usb_ring_lock, flags);
-    resp = &up->usb_ring_base->
-        ring[MASK_USBIF_IDX(up->usb_resp_prod)].resp;
-    resp->id        = id;
-    resp->operation = op;
-    resp->status    = st;
-    resp->data      = inband;
-    resp->length = length;
-    wmb(); /* Ensure other side can see the response fields. */
-    up->usb_ring_base->resp_prod = ++up->usb_resp_prod;
-    spin_unlock_irqrestore(&up->usb_ring_lock, flags);
-
-    /* Kick the relevant domain. */
-    notify_via_evtchn(up->evtchn);
-}
-
-/**
- * usbif_claim_port - claim devices on a port on behalf of guest
- *
- * Once completed, this will ensure that any device attached to that
- * port is claimed by this driver for use by the guest.
- */
-int usbif_claim_port(usbif_be_claim_port_t *msg)
-{
-    owned_port_t *o_p;
-    
-    /* Sanity... */
-    if ( usbif_find_port(msg->path) != NULL )
-    {
-        printk("usbback: Attempted to claim USB port "
-               "we already own!\n");
-        return -EINVAL;
-    }
-
-    spin_lock_irq(&owned_ports_lock);
-    
-    /* No need for a slab cache - this should be infrequent. */
-    o_p = kmalloc(sizeof(owned_port_t), GFP_KERNEL);
-
-    o_p->enabled = 0;
-    o_p->usbif_priv = usbif_find(msg->domid);
-    o_p->guest_port = msg->usbif_port;
-    o_p->dev_present = 0;
-    o_p->guest_address = 0; /* Default address. */
-
-    strcpy(o_p->path, msg->path);
-
-    list_add(&o_p->list, &owned_ports);
-
-    printk("usbback: Claimed USB port (%s) for %d.%d\n", o_p->path,
-          msg->domid, msg->usbif_port);
-
-    spin_unlock_irq(&owned_ports_lock);
-
-    /* Force a reprobe for unclaimed devices. */
-    usb_scan_devices();
-
-    return 0;
-}
-
-owned_port_t *find_port_for_request(usbif_priv_t *up, usbif_request_t *req)
-{
-    unsigned long flags;
-    struct list_head *port;
-
-    /* I'm assuming this is not called from IRQ context - correct?  I think
-     * it's probably only called in response to control messages or plug events
-     * in the USB hub kernel thread, so should be OK. */
-    spin_lock_irqsave(&owned_ports_lock, flags);
-    list_for_each(port, &owned_ports)
-    {
-        owned_port_t *p = list_entry(port, owned_port_t, list);
-        if(p->usbif_priv == up && p->guest_address == req->devnum && p->enabled )
-         {
-#if 0
-              printk("Found port for devnum %d\n", req->devnum);
-
-              dump_port(p);
-#endif
-              return p;
-         }
-    }
-    spin_unlock_irqrestore(&owned_ports_lock, flags);
-
-    return NULL;    
-}
-
-owned_port_t *usbif_find_port(char *path)
-{
-    struct list_head *port;
-    unsigned long flags;
-
-    spin_lock_irqsave(&owned_ports_lock, flags);
-    list_for_each(port, &owned_ports)
-    {
-        owned_port_t *p = list_entry(port, owned_port_t, list);
-        if(!strcmp(path, p->path))
-        {
-            spin_unlock_irqrestore(&owned_ports_lock, flags);
-            return p;
-        }
-    }
-    spin_unlock_irqrestore(&owned_ports_lock, flags);
-
-    return NULL;
-}
-
-
-static void *probe(struct usb_device *dev, unsigned iface,
-           const struct usb_device_id *id)
-{
-    owned_port_t *p;
-
-    /* We don't care what the device is - if we own the port, we want it.  We
-     * don't deal with device-specifics in this driver, so we don't care what
-     * the device actually is ;-) */
-    if ( ( p = usbif_find_port(dev->devpath) ) != NULL )
-    {
-        printk("usbback: claimed device attached to owned port\n");
-
-        p->dev_present = 1;
-        p->dev = dev;
-        set_bit(iface, &p->ifaces);
-        
-        return p->usbif_priv;
-    }
-    else
-        printk("usbback: hotplug for non-owned port (%s), ignoring\n", dev->devpath);
-   
-
-    return NULL;
-}
-
-static void disconnect(struct usb_device *dev, void *usbif)
-{
-    /* Note the device is removed so we can tell the guest when it probes. */
-    owned_port_t *port = usbif_find_port(dev->devpath);
-    port->dev_present = 0;
-    port->dev = NULL;
-    port->ifaces = 0;
-}
-
-
-struct usb_driver driver =
-{
-    .owner      = THIS_MODULE,
-    .name       = "Xen USB Backend",
-    .probe      = probe,
-    .disconnect = disconnect,
-    .id_table   = NULL,
-};
-
-/* __usbif_release_port - internal mechanics for releasing a port */
-void __usbif_release_port(owned_port_t *p)
-{
-    int i;
-
-    for ( i = 0; p->ifaces != 0; i++)
-        if ( p->ifaces & 1 << i )
-        {
-            usb_driver_release_interface(&driver, usb_ifnum_to_if(p->dev, i));
-            clear_bit(i, &p->ifaces);
-        }
-    list_del(&p->list);
-
-    /* Reset the real device.  We don't simulate disconnect / probe for other
-     * drivers in this kernel because we assume the device is completely under
-     * the control of ourselves (i.e. the guest!).  This should ensure that the
-     * device is in a sane state for the next customer ;-) */
-/*     if ( p->dev != NULL) */
-/*         usb_reset_device(p->dev); */
-
-    kfree(p);
-}
-
-
-/**
- * usbif_release_port - stop claiming devices on a port on behalf of guest
- */
-void usbif_release_port(usbif_be_release_port_t *msg)
-{
-    owned_port_t *p;
-
-    spin_lock_irq(&owned_ports_lock);
-    p = usbif_find_port(msg->path);
-    __usbif_release_port(p);
-    spin_unlock_irq(&owned_ports_lock);
-}
-
-void usbif_release_ports(usbif_priv_t *up)
-{
-    struct list_head *port, *tmp;
-    unsigned long flags;
-    
-    spin_lock_irqsave(&owned_ports_lock, flags);
-    list_for_each_safe(port, tmp, &owned_ports)
-    {
-        owned_port_t *p = list_entry(port, owned_port_t, list);
-        if ( p->usbif_priv == up )
-            __usbif_release_port(p);
-    }
-    spin_unlock_irqrestore(&owned_ports_lock, flags);
-}
-
-static int __init usbif_init(void)
-{
-    int i;
-
-    if ( !(xen_start_info.flags & SIF_INITDOMAIN) &&
-         !(xen_start_info.flags & SIF_USB_BE_DOMAIN) )
-        return 0;
-    
-    INIT_LIST_HEAD(&owned_ports);
-
-    usb_register(&driver);
-
-    usbif_interface_init();
-
-    if ( (mmap_vstart = allocate_empty_lowmem_region(MMAP_PAGES)) == 0 )
-        BUG();
-
-    pending_cons = 0;
-    pending_prod = MAX_PENDING_REQS;
-    memset(pending_reqs, 0, sizeof(pending_reqs));
-    for ( i = 0; i < MAX_PENDING_REQS; i++ )
-        pending_ring[i] = i;
-
-    spin_lock_init(&usbio_schedule_list_lock);
-    INIT_LIST_HEAD(&usbio_schedule_list);
-
-    if ( kernel_thread(usbio_schedule, 0, CLONE_FS | CLONE_FILES) < 0 )
-        BUG();
-    
-    usbif_ctrlif_init();
-
-    spin_lock_init(&owned_ports_lock);
-
-    printk("Xen USB Backend Initialised");
-
-    return 0;
-}
-
-__initcall(usbif_init);
diff --git a/linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/frontend/Makefile b/linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/frontend/Makefile
deleted file mode 100644 (file)
index 032d02d..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-O_TARGET := drv.o
-obj-y := main.o
-include $(TOPDIR)/Rules.make
diff --git a/linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/frontend/main.c b/linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/frontend/main.c
deleted file mode 100644 (file)
index 8cf879c..0000000
+++ /dev/null
@@ -1,1720 +0,0 @@
-/*
- * Xen Virtual USB Frontend Driver 
- *
- * This file contains the first version of the Xen virtual USB hub
- * that I've managed not to delete by mistake (3rd time lucky!).
- *
- * Based on Linux's uhci.c, original copyright notices are displayed
- * below.  Portions also (c) 2004 Intel Research Cambridge
- * and (c) 2004 Mark Williamson
- *
- * Contact <mark.williamson@cl.cam.ac.uk> or
- * <xen-devel@lists.sourceforge.net> regarding this code.
- *
- * Still to be (maybe) implemented:
- * - multiple port
- * - multiple interfaces
- * - migration / backend restart support?
- * - unloading support
- *
- * Differences to a normal host controller:
- * - the backend does most of the mucky stuff so we don't have to do various
- *   things that are necessary for a normal host controller (e.g. FSBR).
- * - we don't have any hardware, so status registers are simulated in software.
- */
-
-/*
- * Universal Host Controller Interface driver for USB.
- *
- * Maintainer: Johannes Erdfelt <johannes@erdfelt.com>
- *
- * (C) Copyright 1999 Linus Torvalds
- * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@erdfelt.com
- * (C) Copyright 1999 Randy Dunlap
- * (C) Copyright 1999 Georg Acher, acher@in.tum.de
- * (C) Copyright 1999 Deti Fliegl, deti@fliegl.de
- * (C) Copyright 1999 Thomas Sailer, sailer@ife.ee.ethz.ch
- * (C) Copyright 1999 Roman Weissgaerber, weissg@vienna.at
- * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
- *               support from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
- * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
- *
- * Intel documents this fairly well, and as far as I know there
- * are no royalties or anything like that, but even so there are
- * people who decided that they want to do the same thing in a
- * completely different way.
- *
- * WARNING! The USB documentation is downright evil. Most of it
- * is just crap, written by a committee. You're better off ignoring
- * most of it, the important stuff is:
- *  - the low-level protocol (fairly simple but lots of small details)
- *  - working around the horridness of the rest
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/smp_lock.h>
-#include <linux/errno.h>
-#include <linux/unistd.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#ifdef CONFIG_USB_DEBUG
-#define DEBUG
-#else
-#undef DEBUG
-#endif
-#include <linux/usb.h>
-
-#include <asm/uaccess.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-
-#include "xhci.h"
-
-#include <linux/pm.h>
-
-#include "../../../../../drivers/usb/hcd.h"
-
-#include "../usbif.h"
-#include <asm/ctrl_if.h>
-#include <asm/xen-public/io/domain_controller.h>
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v1.0"
-#define DRIVER_AUTHOR "Linus 'Frodo Rabbit' Torvalds, Johannes Erdfelt, Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber, Mark Williamson"
-#define DRIVER_DESC "Xen Virtual USB Host Controller Interface driver"
-
-/*
- * debug = 0, no debugging messages
- * debug = 1, dump failed URB's except for stalls
- * debug = 2, dump all failed URB's (including stalls)
- */
-#ifdef DEBUG
-static int debug = 1;
-#else
-static int debug = 0;
-#endif
-MODULE_PARM(debug, "i");
-MODULE_PARM_DESC(debug, "Debug level");
-static char *errbuf;
-#define ERRBUF_LEN    (PAGE_SIZE * 8)
-
-static kmem_cache_t *xhci_up_cachep;   /* urb_priv */
-
-static int rh_submit_urb(struct urb *urb);
-static int rh_unlink_urb(struct urb *urb);
-//static int xhci_get_current_frame_number(struct usb_device *dev);
-static int xhci_unlink_urb(struct urb *urb);
-static void xhci_unlink_generic(struct urb *urb);
-static void xhci_call_completion(struct urb *urb);
-static void xhci_drain_ring(void);
-
-#define MAX_URB_LOOP   2048            /* Maximum number of linked URB's */
-
-struct xhci *xhci;
-
-enum { USBIF_STATE_CONNECTED = 2,
-       USBIF_STATE_DISCONNECTED = 1,
-       USBIF_STATE_CLOSED =0
-};
-
-static int awaiting_reset = 0;
-
-/**
- * xhci_construct_isoc - add isochronous information to a request
- */
-int xhci_construct_isoc(usbif_request_t *req, struct urb *urb)
-{
-        usbif_iso_t *schedule;
-        int i;
-        struct urb_priv *urb_priv = urb->hcpriv;
-        
-        req->num_iso = urb->number_of_packets;
-        schedule = (usbif_iso_t *)__get_free_page(GFP_KERNEL);
-
-        if ( schedule == NULL )
-            return -ENOMEM;
-
-        for ( i = 0; i < req->num_iso; i++ )
-        {
-                schedule[i].buffer_offset = urb->iso_frame_desc[i].offset;
-                schedule[i].length = urb->iso_frame_desc[i].length;
-        }
-
-        urb_priv->schedule = schedule;
-       req->iso_schedule = virt_to_machine(schedule);
-
-        return 0;
-}
-
-#define USBIF_RING_FULL ((xhci->usbif->req_prod - xhci->usb_resp_cons) == USBIF_RING_SIZE)
-
-static void dump_urb(struct urb *urb)
-{
-        printk("dumping urb @ %p\n", urb);
-        
-        printk("hcpriv = %p\n", urb->hcpriv);
-        printk("next = %p\n", urb->next);
-        printk("dev = %p\n", urb->dev);
-        printk("pipe = 0x%lx\n", urb->pipe);
-        printk("status = %d\n", urb->status);
-        printk("transfer_flags = 0x%lx\n", urb->transfer_flags);
-        printk("transfer_buffer = %p\n", urb->transfer_buffer);
-        printk("transfer_buffer_length = %d\n", urb->transfer_buffer_length);
-        printk("actual_length = %d\n", urb->actual_length);
-        printk("bandwidth = %d\n", urb->bandwidth);
-        printk("setup_packet = %p\n", urb->setup_packet);
-       if ( urb->setup_packet != NULL )
-                 printk("setup = { 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n",
-               urb->setup_packet[0], urb->setup_packet[1], urb->setup_packet[2], urb->setup_packet[3],
-               urb->setup_packet[4], urb->setup_packet[5], urb->setup_packet[6], urb->setup_packet[7]);
-        printk("complete = %p\n", urb->complete);
-        printk("interval = %d\n", urb->interval);
-        
-}
-
-
-static int
-xhci_queue_req(struct urb *urb)
-{
-        usbif_request_t *req;
-        usbif_t *usbif = xhci->usbif;
-
-#if 0
-        printk("usbif = %p, req_prod = %d (@ 0x%lx), resp_prod = %d, resp_cons = %d\n",
-               usbif, usbif->req_prod, virt_to_machine(&usbif->req_prod),
-               usbif->resp_prod, xhci->usb_resp_cons);
-#endif
-        
-
-/*     printk("Usbif_priv %p, want IO at 0x%lx\n", urb->hcpriv, virt_to_machine(urb->transfer_buffer)); */
-
-        if ( USBIF_RING_FULL )
-        {
-                printk("xhci_queue_req(): USB ring full, not queuing request\n");
-                return -ENOBUFS;
-        }
-
-        /* Stick something in the shared communications ring. */
-        req = &usbif->ring[MASK_USBIF_IDX(usbif->req_prod)].req;
-
-        req->operation       = USBIF_OP_IO;
-        req->port            = 0; /* We don't care what the port is. */
-        req->id              = (unsigned long) urb->hcpriv;
-        req->transfer_buffer = virt_to_machine(urb->transfer_buffer);
-       req->devnum          = usb_pipedevice(urb->pipe);
-        req->direction       = usb_pipein(urb->pipe);
-       req->speed           = usb_pipeslow(urb->pipe);
-        req->pipe_type       = usb_pipetype(urb->pipe);
-        req->length          = urb->transfer_buffer_length;
-        req->transfer_flags  = urb->transfer_flags;
-       req->endpoint        = usb_pipeendpoint(urb->pipe);
-       req->speed           = usb_pipeslow(urb->pipe);
-       req->timeout         = urb->timeout * (1000 / HZ);
-
-        if ( usb_pipetype(urb->pipe) == 0 ) /* ISO */
-        {
-            int ret = xhci_construct_isoc(req, urb);
-            if ( ret != 0 )
-                return ret;
-        }
-
-       if(urb->setup_packet != NULL)
-                memcpy(req->setup, urb->setup_packet, 8);
-        else
-                memset(req->setup, 0, 8);
-        
-        wmb();
-
-        usbif->req_prod++;
-
-       notify_via_evtchn(xhci->evtchn);
-
-       //      dump_urb(urb);
-
-        return -EINPROGRESS;
-}
-
-static inline usbif_request_t *
-xhci_queue_probe(usbif_vdev_t port)
-{
-        usbif_request_t *req;
-        usbif_t *usbif = xhci->usbif;
-
-#if 0
-       printk("queuing probe: req_prod = %d (@ 0x%lx), resp_prod = %d, resp_cons = %d\n",
-              usbif->req_prod, virt_to_machine(&usbif->req_prod),
-              usbif->resp_prod, xhci->usb_resp_cons);
-#endif
-        
-        if ( USBIF_RING_FULL )
-        {
-                printk("xhci_queue_probe(): USB ring full, not queuing request\n");
-                return NULL;
-        }
-
-        /* Stick something in the shared communications ring. */
-        req = &usbif->ring[MASK_USBIF_IDX(usbif->req_prod)].req;
-
-        req->operation       = USBIF_OP_PROBE;
-        req->port            = port;
-        req->id              = 0;
-        req->transfer_buffer = 0;
-       req->devnum          = 0;
-        req->direction       = 0;
-       req->speed           = 0;
-        req->pipe_type       = 0;
-        req->length          = 0;
-        req->transfer_flags  = 0;
-       req->endpoint        = 0;
-       req->speed           = 0;
-
-        wmb();
-
-        usbif->req_prod++;
-
-       notify_via_evtchn(xhci->evtchn);
-
-        return req;
-}
-
-static int
-xhci_port_reset(usbif_vdev_t port)
-{
-        usbif_request_t *req;
-        usbif_t *usbif = xhci->usbif;
-
-        /* We only reset one port at a time, so we only need one variable per
-         * hub. */
-        awaiting_reset = 1;
-        
-        /* Stick something in the shared communications ring. */
-        req = &usbif->ring[MASK_USBIF_IDX(usbif->req_prod)].req;
-
-        req->operation       = USBIF_OP_RESET;
-        req->port            = port;
-        
-        wmb();
-
-        usbif->req_prod++;
-
-       notify_via_evtchn(xhci->evtchn);
-
-        while ( awaiting_reset > 0 )
-        {
-                mdelay(1);
-                xhci_drain_ring();
-        }
-
-        return awaiting_reset;
-}
-
-static void xhci_show_resp(usbif_response_t *r)
-{
-        printk("id=0x%lx, op=0x%x, data=0x%x, status=0x%x, length=0x%lx\n",
-               r->id, r->operation, r->data, r->status, r->length);
-}
-
-
-/*
- * Only the USB core should call xhci_alloc_dev and xhci_free_dev
- */
-static int xhci_alloc_dev(struct usb_device *dev)
-{
-       return 0;
-}
-
-static int xhci_free_dev(struct usb_device *dev)
-{
-       return 0;
-}
-
-static inline void xhci_add_complete(struct urb *urb)
-{
-       struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-       unsigned long flags;
-
-       spin_lock_irqsave(&xhci->complete_list_lock, flags);
-       list_add_tail(&urbp->complete_list, &xhci->complete_list);
-       spin_unlock_irqrestore(&xhci->complete_list_lock, flags);
-}
-
-/* When this returns, the owner of the URB may free its
- * storage.
- *
- * We spin and wait for the URB to complete before returning.
- */
-static void xhci_delete_urb(struct urb *urb)
-{
-        struct urb_priv *urbp;
-
-       urbp = urb->hcpriv;
-
-        /* If there's no urb_priv structure for this URB then it can't have
-         * been submitted at all. */
-       if ( urbp == NULL )
-               return;
-
-       /* For now we just spin until the URB completes.  It shouldn't take too
-         * long and we don't expect to have to do this very often. */
-       while ( urb->status == -EINPROGRESS )
-        {
-            xhci_drain_ring();
-            mdelay(1);
-        }
-
-       /* Now we know that further transfers to the buffer won't
-        * occur, so we can safely return. */
-}
-
-static struct urb_priv *xhci_alloc_urb_priv(struct urb *urb)
-{
-       struct urb_priv *urbp;
-
-       urbp = kmem_cache_alloc(xhci_up_cachep, SLAB_ATOMIC);
-       if (!urbp) {
-               err("xhci_alloc_urb_priv: couldn't allocate memory for urb_priv\n");
-               return NULL;
-       }
-
-       memset((void *)urbp, 0, sizeof(*urbp));
-
-       urbp->inserttime = jiffies;
-       urbp->urb = urb;
-       urbp->dev = urb->dev;
-       
-       INIT_LIST_HEAD(&urbp->complete_list);
-
-       urb->hcpriv = urbp;
-
-       return urbp;
-}
-
-/*
- * MUST be called with urb->lock acquired
- */
-/* When is this called?  Do we need to stop the transfer (as we
- * currently do)? */
-static void xhci_destroy_urb_priv(struct urb *urb)
-{
-    struct urb_priv *urbp;
-    
-    urbp = (struct urb_priv *)urb->hcpriv;
-    if (!urbp)
-        return;
-
-    if (!list_empty(&urb->urb_list))
-        warn("xhci_destroy_urb_priv: urb %p still on xhci->urb_list or xhci->remove_list", urb);
-    
-    if (!list_empty(&urbp->complete_list))
-        warn("xhci_destroy_urb_priv: urb %p still on xhci->complete_list", urb);
-    
-    kmem_cache_free(xhci_up_cachep, urb->hcpriv);
-
-    urb->hcpriv = NULL;
-}
-
-/**
- * Try to find URBs in progress on the same pipe to the same device.
- *
- * MUST be called with xhci->urb_list_lock acquired
- */
-static struct urb *xhci_find_urb_ep(struct xhci *xhci, struct urb *urb)
-{
-       struct list_head *tmp, *head;
-
-       /* We don't match Isoc transfers since they are special */
-       if (usb_pipeisoc(urb->pipe))
-               return NULL;
-
-       head = &xhci->urb_list;
-       tmp = head->next;
-       while (tmp != head) {
-               struct urb *u = list_entry(tmp, struct urb, urb_list);
-
-               tmp = tmp->next;
-
-               if (u->dev == urb->dev && u->pipe == urb->pipe &&
-                   u->status == -EINPROGRESS)
-                       return u;
-       }
-
-       return NULL;
-}
-
-static int xhci_submit_urb(struct urb *urb)
-{
-       int ret = -EINVAL;
-       unsigned long flags;
-       struct urb *eurb;
-       int bustime;
-
-#if 0
-        printk("submitting urb @ %p for dev @ %p, devnum = %d path %s\n",
-               urb, urb->dev, urb->dev->devnum, urb->dev->devpath);
-#endif
-
-       if (!urb)
-               return -EINVAL;
-
-       if (!urb->dev || !urb->dev->bus || !urb->dev->bus->hcpriv) {
-               warn("xhci_submit_urb: urb %p belongs to disconnected device or bus?", urb);
-               return -ENODEV;
-       }
-
-        if ( urb->dev->devpath == NULL )
-        {
-                printk("BARF!\n");
-                BUG();
-        }
-        
-        
-
-       usb_inc_dev_use(urb->dev);
-
-       spin_lock_irqsave(&xhci->urb_list_lock, flags);
-       spin_lock(&urb->lock);
-
-       if (urb->status == -EINPROGRESS || urb->status == -ECONNRESET ||
-           urb->status == -ECONNABORTED) {
-               dbg("xhci_submit_urb: urb not available to submit (status = %d)", urb->status);
-               /* Since we can have problems on the out path */
-               spin_unlock(&urb->lock);
-               spin_unlock_irqrestore(&xhci->urb_list_lock, flags);
-               usb_dec_dev_use(urb->dev);
-
-               return ret;
-       }
-
-       INIT_LIST_HEAD(&urb->urb_list);
-       if (!xhci_alloc_urb_priv(urb)) {
-               ret = -ENOMEM;
-
-               goto out;
-       }
-
-        ( (struct urb_priv *)urb->hcpriv )->in_progress = 1;
-
-       eurb = xhci_find_urb_ep(xhci, urb);
-       if (eurb && !(urb->transfer_flags & USB_QUEUE_BULK)) {
-               ret = -ENXIO;
-
-               goto out;
-       }
-
-       /* Short circuit the virtual root hub */
-       if (urb->dev == xhci->rh.dev) {
-               ret = rh_submit_urb(urb);
-
-               goto out;
-       }
-
-       if ( usb_pipedevice(urb->pipe) == 1 )
-         printk("dev = %p, dev->path = %s, rh.dev = %p, rh.dev.devnum = %d rh.dev->path = %s!\n",
-                urb->dev, urb->dev->devpath, xhci->rh.dev, xhci->rh.dev->devnum, xhci->rh.dev->devpath);
-
-       switch (usb_pipetype(urb->pipe)) {
-       case PIPE_CONTROL:
-               ret = xhci_queue_req(urb);
-               break;
-       case PIPE_INTERRUPT:
-               if (urb->bandwidth == 0) {      /* not yet checked/allocated */
-                       bustime = usb_check_bandwidth(urb->dev, urb);
-                       if (bustime < 0)
-                               ret = bustime;
-                       else {
-                               ret = xhci_queue_req(urb);
-                               if (ret == -EINPROGRESS)
-                                       usb_claim_bandwidth(urb->dev, urb, bustime, 0);
-                       }
-               } else          /* bandwidth is already set */
-                       ret = xhci_queue_req(urb);
-               break;
-       case PIPE_BULK:
-               ret = xhci_queue_req(urb);
-               break;
-       case PIPE_ISOCHRONOUS:
-               if (urb->bandwidth == 0) {      /* not yet checked/allocated */
-                       if (urb->number_of_packets <= 0) {
-                               ret = -EINVAL;
-                               break;
-                       }
-                       bustime = usb_check_bandwidth(urb->dev, urb);
-                       if (bustime < 0) {
-                               ret = bustime;
-                               break;
-                       }
-
-                       ret = xhci_queue_req(urb);
-                       if (ret == -EINPROGRESS)
-                               usb_claim_bandwidth(urb->dev, urb, bustime, 1);
-               } else          /* bandwidth is already set */
-                       ret = xhci_queue_req(urb);
-               break;
-       }
-
-out:
-       urb->status = ret;
-
-       if (ret == -EINPROGRESS) {
-               /* We use _tail to make find_urb_ep more efficient */
-               list_add_tail(&urb->urb_list, &xhci->urb_list);
-
-               spin_unlock(&urb->lock);
-               spin_unlock_irqrestore(&xhci->urb_list_lock, flags);
-
-               return 0;
-       }
-
-       xhci_unlink_generic(urb);
-
-       spin_unlock(&urb->lock);
-       spin_unlock_irqrestore(&xhci->urb_list_lock, flags);
-
-       /* Only call completion if it was successful */
-       if (!ret)
-               xhci_call_completion(urb);
-
-       return ret;
-}
-
-/*
- * Return the result of a transfer
- *
- * MUST be called with urb_list_lock acquired
- */
-static void xhci_transfer_result(struct xhci *xhci, struct urb *urb)
-{
-       int ret = 0;
-       unsigned long flags;
-       struct urb_priv *urbp;
-
-       /* The root hub is special */
-       if (urb->dev == xhci->rh.dev)
-               return;
-
-       spin_lock_irqsave(&urb->lock, flags);
-
-       urbp = (struct urb_priv *)urb->hcpriv;
-
-        if ( ( (struct urb_priv *)urb->hcpriv )->in_progress )
-                ret = -EINPROGRESS;
-
-        if (urb->actual_length < urb->transfer_buffer_length) {
-                if (urb->transfer_flags & USB_DISABLE_SPD) {
-                        ret = -EREMOTEIO;
-                }
-        }
-
-       if (urb->status == -EPIPE)
-        {
-                ret = urb->status;
-               /* endpoint has stalled - mark it halted */
-               usb_endpoint_halt(urb->dev, usb_pipeendpoint(urb->pipe),
-                                  usb_pipeout(urb->pipe));
-        }
-
-       if ((debug == 1 && ret != 0 && ret != -EPIPE) ||
-            (ret != 0 && debug > 1)) {
-               /* Some debugging code */
-               dbg("xhci_result_interrupt/bulk() failed with status %x",
-                       status);
-       }
-
-       if (ret == -EINPROGRESS)
-               goto out;
-
-       switch (usb_pipetype(urb->pipe)) {
-       case PIPE_CONTROL:
-       case PIPE_BULK:
-       case PIPE_ISOCHRONOUS:
-               /* Release bandwidth for Interrupt or Isoc. transfers */
-               /* Spinlock needed ? */
-               if (urb->bandwidth)
-                       usb_release_bandwidth(urb->dev, urb, 1);
-               xhci_unlink_generic(urb);
-               break;
-       case PIPE_INTERRUPT:
-               /* Interrupts are an exception */
-               if (urb->interval)
-                       goto out_complete;
-
-               /* Release bandwidth for Interrupt or Isoc. transfers */
-               /* Spinlock needed ? */
-               if (urb->bandwidth)
-                       usb_release_bandwidth(urb->dev, urb, 0);
-               xhci_unlink_generic(urb);
-               break;
-       default:
-               info("xhci_transfer_result: unknown pipe type %d for urb %p\n",
-                       usb_pipetype(urb->pipe), urb);
-       }
-
-       /* Remove it from xhci->urb_list */
-       list_del_init(&urb->urb_list);
-
-out_complete:
-       xhci_add_complete(urb);
-
-out:
-       spin_unlock_irqrestore(&urb->lock, flags);
-}
-
-/*
- * MUST be called with urb->lock acquired
- */
-static void xhci_unlink_generic(struct urb *urb)
-{
-       struct urb_priv *urbp = urb->hcpriv;
-
-       /* We can get called when urbp allocation fails, so check */
-       if (!urbp)
-               return;
-
-        /* ??? This function is now so minimal it doesn't do much.  Do we really
-         * need it? */
-
-       xhci_delete_urb(urb);
-}
-
-static int xhci_unlink_urb(struct urb *urb)
-{
-       unsigned long flags;
-       struct urb_priv *urbp = urb->hcpriv;
-
-       if (!urb)
-               return -EINVAL;
-
-       if (!urb->dev || !urb->dev->bus || !urb->dev->bus->hcpriv)
-               return -ENODEV;
-
-       spin_lock_irqsave(&xhci->urb_list_lock, flags);
-       spin_lock(&urb->lock);
-
-       /* Release bandwidth for Interrupt or Isoc. transfers */
-       /* Spinlock needed ? */
-       if (urb->bandwidth) {
-               switch (usb_pipetype(urb->pipe)) {
-               case PIPE_INTERRUPT:
-                       usb_release_bandwidth(urb->dev, urb, 0);
-                       break;
-               case PIPE_ISOCHRONOUS:
-                       usb_release_bandwidth(urb->dev, urb, 1);
-                       break;
-               default:
-                       break;
-               }
-       }
-
-       if (urb->status != -EINPROGRESS) {
-               spin_unlock(&urb->lock);
-               spin_unlock_irqrestore(&xhci->urb_list_lock, flags);
-               return 0;
-       }
-
-       list_del_init(&urb->urb_list);
-
-       xhci_unlink_generic(urb);
-
-       /* Short circuit the virtual root hub */
-       if (urb->dev == xhci->rh.dev) {
-               rh_unlink_urb(urb);
-
-               spin_unlock(&urb->lock);
-               spin_unlock_irqrestore(&xhci->urb_list_lock, flags);
-
-               xhci_call_completion(urb);
-       } else {
-               if (urb->transfer_flags & USB_ASYNC_UNLINK) {
-                       urbp->status = urb->status = -ECONNABORTED;
-
-                       spin_lock(&xhci->urb_remove_list_lock);
-
-                       list_add(&urb->urb_list, &xhci->urb_remove_list);
-
-                       spin_unlock(&xhci->urb_remove_list_lock);
-
-                       spin_unlock(&urb->lock);
-                       spin_unlock_irqrestore(&xhci->urb_list_lock, flags);
-
-               } else {
-                       urb->status = -ENOENT;
-
-                       spin_unlock(&urb->lock);
-                       spin_unlock_irqrestore(&xhci->urb_list_lock, flags);
-
-                       if (in_interrupt()) {   /* wait at least 1 frame */
-                               static int errorcount = 10;
-
-                               if (errorcount--)
-                                       dbg("xhci_unlink_urb called from interrupt for urb %p", urb);
-                               udelay(1000);
-                       } else
-                               schedule_timeout(1+1*HZ/1000); 
-
-                       xhci_call_completion(urb);
-               }
-       }
-
-       return 0;
-}
-
-
-struct usb_operations xhci_device_operations = {
-       .allocate = xhci_alloc_dev,
-       .deallocate = xhci_free_dev,
-        /* It doesn't look like any drivers actually care what the frame number
-        * is at the moment!  If necessary, we could approximate the current
-        * frame nubmer by passing it from the backend in response messages. */
-       .get_frame_number = NULL,
-       .submit_urb = xhci_submit_urb,
-       .unlink_urb = xhci_unlink_urb
-};
-
-/* Virtual Root Hub */
-
-static __u8 root_hub_dev_des[] =
-{
-       0x12,                   /*  __u8  bLength; */
-       0x01,                   /*  __u8  bDescriptorType; Device */
-       0x00,                   /*  __u16 bcdUSB; v1.0 */
-       0x01,
-       0x09,                   /*  __u8  bDeviceClass; HUB_CLASSCODE */
-       0x00,                   /*  __u8  bDeviceSubClass; */
-       0x00,                   /*  __u8  bDeviceProtocol; */
-       0x08,                   /*  __u8  bMaxPacketSize0; 8 Bytes */
-       0x00,                   /*  __u16 idVendor; */
-       0x00,
-       0x00,                   /*  __u16 idProduct; */
-       0x00,
-       0x00,                   /*  __u16 bcdDevice; */
-       0x00,
-       0x00,                   /*  __u8  iManufacturer; */
-       0x02,                   /*  __u8  iProduct; */
-       0x01,                   /*  __u8  iSerialNumber; */
-       0x01                    /*  __u8  bNumConfigurations; */
-};
-
-
-/* Configuration descriptor */
-static __u8 root_hub_config_des[] =
-{
-       0x09,                   /*  __u8  bLength; */
-       0x02,                   /*  __u8  bDescriptorType; Configuration */
-       0x19,                   /*  __u16 wTotalLength; */
-       0x00,
-       0x01,                   /*  __u8  bNumInterfaces; */
-       0x01,                   /*  __u8  bConfigurationValue; */
-       0x00,                   /*  __u8  iConfiguration; */
-       0x40,                   /*  __u8  bmAttributes;
-                                       Bit 7: Bus-powered, 6: Self-powered,
-                                       Bit 5 Remote-wakeup, 4..0: resvd */
-       0x00,                   /*  __u8  MaxPower; */
-
-       /* interface */
-       0x09,                   /*  __u8  if_bLength; */
-       0x04,                   /*  __u8  if_bDescriptorType; Interface */
-       0x00,                   /*  __u8  if_bInterfaceNumber; */
-       0x00,                   /*  __u8  if_bAlternateSetting; */
-       0x01,                   /*  __u8  if_bNumEndpoints; */
-       0x09,                   /*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
-       0x00,                   /*  __u8  if_bInterfaceSubClass; */
-       0x00,                   /*  __u8  if_bInterfaceProtocol; */
-       0x00,                   /*  __u8  if_iInterface; */
-
-       /* endpoint */
-       0x07,                   /*  __u8  ep_bLength; */
-       0x05,                   /*  __u8  ep_bDescriptorType; Endpoint */
-       0x81,                   /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
-       0x03,                   /*  __u8  ep_bmAttributes; Interrupt */
-       0x08,                   /*  __u16 ep_wMaxPacketSize; 8 Bytes */
-       0x00,
-       0xff                    /*  __u8  ep_bInterval; 255 ms */
-};
-
-static __u8 root_hub_hub_des[] =
-{
-       0x09,                   /*  __u8  bLength; */
-       0x29,                   /*  __u8  bDescriptorType; Hub-descriptor */
-       0x02,                   /*  __u8  bNbrPorts; */
-       0x00,                   /* __u16  wHubCharacteristics; */
-       0x00,
-       0x01,                   /*  __u8  bPwrOn2pwrGood; 2ms */
-       0x00,                   /*  __u8  bHubContrCurrent; 0 mA */
-       0x00,                   /*  __u8  DeviceRemovable; *** 7 Ports max *** */
-       0xff                    /*  __u8  PortPwrCtrlMask; *** 7 ports max *** */
-};
-
-/* prepare Interrupt pipe transaction data; HUB INTERRUPT ENDPOINT */
-static int rh_send_irq(struct urb *urb)
-{
-       struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-        xhci_port_t *ports = xhci->rh.ports;
-       unsigned long flags;
-       int i, len = 1;
-       __u16 data = 0;
-
-       spin_lock_irqsave(&urb->lock, flags);
-       for (i = 0; i < xhci->rh.numports; i++) {
-                /* MAW: No idea what the old code was doing here or why it worked.
-                * This implementation sets a bit if anything at all has changed on the 
-                * port, as per USB spec 11.12 */
-               data |= (ports[i].cs_chg || ports[i].pe_chg )
-                        ? (1 << (i + 1))
-                        : 0;
-
-               len = (i + 1) / 8 + 1;
-       }
-
-       *(__u16 *) urb->transfer_buffer = cpu_to_le16(data);
-       urb->actual_length = len;
-       urbp->status = 0;
-
-       spin_unlock_irqrestore(&urb->lock, flags);
-
-       if ((data > 0) && (xhci->rh.send != 0)) {
-               dbg("root-hub INT complete: data: %x", data);
-               xhci_call_completion(urb);
-       }
-
-       return 0;
-}
-
-/* Virtual Root Hub INTs are polled by this timer every "interval" ms */
-static int rh_init_int_timer(struct urb *urb);
-
-static void rh_int_timer_do(unsigned long ptr)
-{
-       struct urb *urb = (struct urb *)ptr;
-       struct list_head list, *tmp, *head;
-       unsigned long flags;
-       int i;
-
-       for ( i = 0; i < xhci->rh.numports; i++)
-                xhci_queue_probe(i);
-
-       if (xhci->rh.send)
-               rh_send_irq(urb);
-
-       INIT_LIST_HEAD(&list);
-
-       spin_lock_irqsave(&xhci->urb_list_lock, flags);
-       head = &xhci->urb_list;
-       tmp = head->next;
-       while (tmp != head) {
-               struct urb *u = list_entry(tmp, struct urb, urb_list);
-               struct urb_priv *up = (struct urb_priv *)u->hcpriv;
-
-               tmp = tmp->next;
-
-               spin_lock(&u->lock);
-
-               /* Check if the URB timed out */
-               if (u->timeout && time_after_eq(jiffies, up->inserttime + u->timeout)) {
-                       list_del(&u->urb_list);
-                       list_add_tail(&u->urb_list, &list);
-               }
-
-               spin_unlock(&u->lock);
-       }
-       spin_unlock_irqrestore(&xhci->urb_list_lock, flags);
-
-       head = &list;
-       tmp = head->next;
-       while (tmp != head) {
-               struct urb *u = list_entry(tmp, struct urb, urb_list);
-
-               tmp = tmp->next;
-
-               u->transfer_flags |= USB_ASYNC_UNLINK | USB_TIMEOUT_KILLED;
-               xhci_unlink_urb(u);
-       }
-
-       rh_init_int_timer(urb);
-}
-
-/* Root Hub INTs are polled by this timer */
-static int rh_init_int_timer(struct urb *urb)
-{
-       xhci->rh.interval = urb->interval;
-       init_timer(&xhci->rh.rh_int_timer);
-       xhci->rh.rh_int_timer.function = rh_int_timer_do;
-       xhci->rh.rh_int_timer.data = (unsigned long)urb;
-       xhci->rh.rh_int_timer.expires = jiffies + (HZ * (urb->interval < 30 ? 30 : urb->interval)) / 1000;
-       add_timer(&xhci->rh.rh_int_timer);
-
-       return 0;
-}
-
-#define OK(x)                  len = (x); break
-
-/* Root Hub Control Pipe */
-static int rh_submit_urb(struct urb *urb)
-{
-       unsigned int pipe = urb->pipe;
-       struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *)urb->setup_packet;
-       void *data = urb->transfer_buffer;
-       int leni = urb->transfer_buffer_length;
-       int len = 0;
-       xhci_port_t *status;
-       int stat = 0;
-       int i;
-       int retstatus;
-        unsigned long flags;
-        
-       __u16 cstatus;
-       __u16 bmRType_bReq;
-       __u16 wValue;
-       __u16 wIndex;
-       __u16 wLength;
-
-       if (usb_pipetype(pipe) == PIPE_INTERRUPT) {
-               xhci->rh.urb = urb;
-               xhci->rh.send = 1;
-               xhci->rh.interval = urb->interval;
-               rh_init_int_timer(urb);
-
-               return -EINPROGRESS;
-       }
-
-       bmRType_bReq = cmd->bRequestType | cmd->bRequest << 8;
-       wValue = le16_to_cpu(cmd->wValue);
-       wIndex = le16_to_cpu(cmd->wIndex);
-       wLength = le16_to_cpu(cmd->wLength);
-
-       for (i = 0; i < 8; i++)
-               xhci->rh.c_p_r[i] = 0;
-
-        status = &xhci->rh.ports[wIndex - 1];
-
-        spin_lock_irqsave(&xhci->rh.port_state_lock, flags);
-
-       switch (bmRType_bReq) {
-               /* Request Destination:
-                  without flags: Device,
-                  RH_INTERFACE: interface,
-                  RH_ENDPOINT: endpoint,
-                  RH_CLASS means HUB here,
-                  RH_OTHER | RH_CLASS  almost ever means HUB_PORT here
-               */
-
-       case RH_GET_STATUS:
-               *(__u16 *)data = cpu_to_le16(1);
-               OK(2);
-       case RH_GET_STATUS | RH_INTERFACE:
-               *(__u16 *)data = cpu_to_le16(0);
-               OK(2);
-       case RH_GET_STATUS | RH_ENDPOINT:
-               *(__u16 *)data = cpu_to_le16(0);
-               OK(2);
-       case RH_GET_STATUS | RH_CLASS:
-               *(__u32 *)data = cpu_to_le32(0);
-               OK(4);          /* hub power */
-       case RH_GET_STATUS | RH_OTHER | RH_CLASS:
-               cstatus = (status->cs_chg) |
-                       (status->pe_chg << 1) |
-                       (xhci->rh.c_p_r[wIndex - 1] << 4);
-               retstatus = (status->ccs) |
-                       (status->pe << 1) |
-                       (status->susp << 2) |
-                       (status->pr << 8) |
-                       (1 << 8) |      /* power on */
-                       (status->lsda << 9);
-               *(__u16 *)data = cpu_to_le16(retstatus);
-               *(__u16 *)(data + 2) = cpu_to_le16(cstatus);
-               OK(4);
-       case RH_CLEAR_FEATURE | RH_ENDPOINT:
-               switch (wValue) {
-               case RH_ENDPOINT_STALL:
-                       OK(0);
-               }
-               break;
-       case RH_CLEAR_FEATURE | RH_CLASS:
-               switch (wValue) {
-               case RH_C_HUB_OVER_CURRENT:
-                       OK(0);  /* hub power over current */
-               }
-               break;
-       case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
-               switch (wValue) {
-               case RH_PORT_ENABLE:
-                        status->pe     = 0;
-                       OK(0);
-               case RH_PORT_SUSPEND:
-                        status->susp   = 0;
-                       OK(0);
-               case RH_PORT_POWER:
-                       OK(0);  /* port power */
-               case RH_C_PORT_CONNECTION:
-                        status->cs_chg = 0;
-                       OK(0);
-               case RH_C_PORT_ENABLE:
-                        status->pe_chg = 0;
-                       OK(0);
-               case RH_C_PORT_SUSPEND:
-                       /*** WR_RH_PORTSTAT(RH_PS_PSSC); */
-                       OK(0);
-               case RH_C_PORT_OVER_CURRENT:
-                       OK(0);  /* port power over current */
-               case RH_C_PORT_RESET:
-                       xhci->rh.c_p_r[wIndex - 1] = 0;
-                       OK(0);
-               }
-               break;
-       case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
-               switch (wValue) {
-               case RH_PORT_SUSPEND:
-                        status->susp = 1;      
-                       OK(0);
-               case RH_PORT_RESET:
-                {
-                        int ret;
-                        xhci->rh.c_p_r[wIndex - 1] = 1;
-                        status->pr = 0;
-                        status->pe = 1;
-                        ret = xhci_port_reset(wIndex - 1);
-                        /* XXX MAW: should probably cancel queued transfers during reset... *\/ */
-                        if ( ret == 0 ) { OK(0); }
-                        else { return ret; }
-                }
-                break;
-               case RH_PORT_POWER:
-                       OK(0); /* port power ** */
-               case RH_PORT_ENABLE:
-                        status->pe = 1;
-                       OK(0);
-               }
-               break;
-       case RH_SET_ADDRESS:
-         printk("setting root hub device to %d\n", wValue);
-               xhci->rh.devnum = wValue;
-               OK(0);
-       case RH_GET_DESCRIPTOR:
-               switch ((wValue & 0xff00) >> 8) {
-               case 0x01:      /* device descriptor */
-                       len = min_t(unsigned int, leni,
-                                 min_t(unsigned int,
-                                     sizeof(root_hub_dev_des), wLength));
-                       memcpy(data, root_hub_dev_des, len);
-                       OK(len);
-               case 0x02:      /* configuration descriptor */
-                       len = min_t(unsigned int, leni,
-                                 min_t(unsigned int,
-                                     sizeof(root_hub_config_des), wLength));
-                       memcpy (data, root_hub_config_des, len);
-                       OK(len);
-               case 0x03:      /* string descriptors */
-                       len = usb_root_hub_string (wValue & 0xff,
-                               0, "XHCI-alt",
-                               data, wLength);
-                       if (len > 0) {
-                               OK(min_t(int, leni, len));
-                       } else 
-                               stat = -EPIPE;
-               }
-               break;
-       case RH_GET_DESCRIPTOR | RH_CLASS:
-               root_hub_hub_des[2] = xhci->rh.numports;
-               len = min_t(unsigned int, leni,
-                         min_t(unsigned int, sizeof(root_hub_hub_des), wLength));
-               memcpy(data, root_hub_hub_des, len);
-               OK(len);
-       case RH_GET_CONFIGURATION:
-               *(__u8 *)data = 0x01;
-               OK(1);
-       case RH_SET_CONFIGURATION:
-               OK(0);
-       case RH_GET_INTERFACE | RH_INTERFACE:
-               *(__u8 *)data = 0x00;
-               OK(1);
-       case RH_SET_INTERFACE | RH_INTERFACE:
-               OK(0);
-       default:
-               stat = -EPIPE;
-       }
-
-        spin_unlock_irqrestore(&xhci->rh.port_state_lock, flags);
-
-       urb->actual_length = len;
-
-       return stat;
-}
-
-/*
- * MUST be called with urb->lock acquired
- */
-static int rh_unlink_urb(struct urb *urb)
-{
-       if (xhci->rh.urb == urb) {
-               urb->status = -ENOENT;
-               xhci->rh.send = 0;
-               xhci->rh.urb = NULL;
-               del_timer(&xhci->rh.rh_int_timer);
-       }
-       return 0;
-}
-
-static void xhci_call_completion(struct urb *urb)
-{
-       struct urb_priv *urbp;
-       struct usb_device *dev = urb->dev;
-       int is_ring = 0, killed, resubmit_interrupt, status;
-       struct urb *nurb;
-       unsigned long flags;
-
-       spin_lock_irqsave(&urb->lock, flags);
-
-       urbp = (struct urb_priv *)urb->hcpriv;
-       if (!urbp || !urb->dev) {
-               spin_unlock_irqrestore(&urb->lock, flags);
-               return;
-       }
-
-       killed = (urb->status == -ENOENT || urb->status == -ECONNABORTED ||
-                       urb->status == -ECONNRESET);
-       resubmit_interrupt = (usb_pipetype(urb->pipe) == PIPE_INTERRUPT &&
-                       urb->interval);
-
-       nurb = urb->next;
-       if (nurb && !killed) {
-               int count = 0;
-
-               while (nurb && nurb != urb && count < MAX_URB_LOOP) {
-                       if (nurb->status == -ENOENT ||
-                           nurb->status == -ECONNABORTED ||
-                           nurb->status == -ECONNRESET) {
-                               killed = 1;
-                               break;
-                       }
-
-                       nurb = nurb->next;
-                       count++;
-               }
-
-               if (count == MAX_URB_LOOP)
-                       err("xhci_call_completion: too many linked URB's, loop? (first loop)");
-
-               /* Check to see if chain is a ring */
-               is_ring = (nurb == urb);
-       }
-
-       status = urbp->status;
-       if (!resubmit_interrupt || killed)
-               /* We don't need urb_priv anymore */
-               xhci_destroy_urb_priv(urb);
-
-       if (!killed)
-               urb->status = status;
-
-       spin_unlock_irqrestore(&urb->lock, flags);
-
-       if (urb->complete)
-               urb->complete(urb);
-
-       if (resubmit_interrupt)
-               /* Recheck the status. The completion handler may have */
-               /*  unlinked the resubmitting interrupt URB */
-               killed = (urb->status == -ENOENT ||
-                         urb->status == -ECONNABORTED ||
-                         urb->status == -ECONNRESET);
-
-       if (resubmit_interrupt && !killed) {
-                if ( urb->dev != xhci->rh.dev )
-                        xhci_queue_req(urb); /* XXX What if this fails? */
-                /* Don't need to resubmit URBs for the virtual root dev. */
-       } else {
-               if (is_ring && !killed) {
-                       urb->dev = dev;
-                       xhci_submit_urb(urb);
-               } else {
-                       /* We decrement the usage count after we're done */
-                       /*  with everything */
-                       usb_dec_dev_use(dev);
-               }
-       }
-}
-
-static void xhci_finish_completion(void)
-{
-       struct list_head *tmp, *head;
-       unsigned long flags;
-
-       spin_lock_irqsave(&xhci->complete_list_lock, flags);
-       head = &xhci->complete_list;
-       tmp = head->next;
-       while (tmp != head) {
-               struct urb_priv *urbp = list_entry(tmp, struct urb_priv, complete_list);
-               struct urb *urb = urbp->urb;
-
-               list_del_init(&urbp->complete_list);
-               spin_unlock_irqrestore(&xhci->complete_list_lock, flags);
-
-               xhci_call_completion(urb);
-
-               spin_lock_irqsave(&xhci->complete_list_lock, flags);
-               head = &xhci->complete_list;
-               tmp = head->next;
-       }
-       spin_unlock_irqrestore(&xhci->complete_list_lock, flags);
-}
-
-void receive_usb_reset(usbif_response_t *resp)
-{
-    awaiting_reset = resp->status;
-    rmb();
-    
-}
-
-void receive_usb_probe(usbif_response_t *resp)
-{
-    spin_lock(&xhci->rh.port_state_lock);
-
-    if ( resp->status > 0 )
-    {
-        if ( resp->status == 1 )
-        {
-/*       printk("hey hey, there's a device on port %d\n", resp->data); */
-
-            /* If theres a device there and there wasn't one before there must
-             * have been a connection status change. */
-            if( xhci->rh.ports[resp->data].cs == 0 )
-           {
-                xhci->rh.ports[resp->data].cs = 1;
-                xhci->rh.ports[resp->data].ccs = 1;
-                xhci->rh.ports[resp->data].cs_chg = 1;
-/*             printk("Look at device on port %d that wasn't there before\n", resp->data); */
-           }
-        }
-        else
-            printk("receive_usb_probe(): unexpected status %d for port %d\n",
-                   resp->status, resp->data);
-    }
-    else if ( resp->status < 0)
-        printk("receive_usb_probe(): got error status %d\n", resp->status);
-
-    spin_unlock(&xhci->rh.port_state_lock);
-}
-
-void receive_usb_io(usbif_response_t *resp)
-{
-        struct urb_priv *urbp = (struct urb_priv *)resp->id;
-        struct urb *urb = urbp->urb;
-
-        urb->actual_length = resp->length;
-       urb->status = resp->status;
-       urbp->status = resp->status;
-        urbp->in_progress = 0;
-
-        if( usb_pipetype(urb->pipe) == 0 ) /* ISO */
-        {
-                int i;
-              
-                /* Copy ISO schedule results back in. */
-
-                for ( i = 0; i < urb->number_of_packets; i++ )
-                {
-                        urb->iso_frame_desc[i].status
-                         = urbp->schedule[i].status;
-                        urb->iso_frame_desc[i].actual_length
-                                = urbp->schedule[i].length;
-                }
-                free_page((unsigned long)urbp->schedule);
-        }
-}
-
-static void xhci_drain_ring(void)
-{
-       struct list_head *tmp, *head;
-       usbif_t *usb_ring = xhci->usbif;
-       usbif_response_t *resp;
-        USBIF_RING_IDX i, rp;
-
-        /* Walk the ring here to get responses, updating URBs to show what
-         * completed. */
-        
-        rp = usb_ring->resp_prod;
-        rmb(); /* Ensure we see queued requests up to 'rp'. */
-
-        /* Take items off the comms ring, taking care not to overflow. */
-        for ( i = xhci->usb_resp_cons; 
-              (i != rp) && ((i-usb_ring->req_prod) != USBIF_RING_SIZE);
-              i++ )
-        {
-            resp = &usb_ring->ring[MASK_USBIF_IDX(i)].resp;
-            
-            /* May need to deal with batching and with putting a ceiling on
-               the number dispatched for performance and anti-dos reasons */
-
-#if 0
-            printk("usbfront: Processing response:\n");
-            printk("          id = 0x%x\n", resp->id);
-            printk("          op = %d\n", resp->operation);
-            printk("          status = %d\n", resp->status);
-            printk("          length = %d\n", resp->length);
-#endif            
-
-            switch ( resp->operation )
-            {
-            case USBIF_OP_PROBE:
-                receive_usb_probe(resp);
-                break;
-                
-            case USBIF_OP_IO:
-                receive_usb_io(resp);
-                break;
-
-            case USBIF_OP_RESET:
-                receive_usb_reset(resp);
-                break;
-
-            default:
-                printk("error: unknown USB io operation response [%d]\n",
-                       usb_ring->ring[i].req.operation);
-                break;
-            }
-        }
-
-        xhci->usb_resp_cons = i;
-
-       /* Walk the list of pending URB's to see which ones completed and do
-         * callbacks, etc. */
-       spin_lock(&xhci->urb_list_lock);
-       head = &xhci->urb_list;
-       tmp = head->next;
-       while (tmp != head) {
-                
-               struct urb *urb = list_entry(tmp, struct urb, urb_list);
-
-               tmp = tmp->next;
-
-               /* Checks the status and does all of the magic necessary */
-               xhci_transfer_result(xhci, urb);
-       }
-       spin_unlock(&xhci->urb_list_lock);
-
-       xhci_finish_completion();
-}
-
-
-static void xhci_interrupt(int irq, void *__xhci, struct pt_regs *regs)
-{
-        xhci_drain_ring();
-}
-
-static void free_xhci(struct xhci *xhci)
-{
-       kfree(xhci);
-}
-
-/* /\* */
-/*  * De-allocate all resources.. */
-/*  *\/ */
-/* static void release_xhci(struct xhci *xhci) */
-/* { */
-/*     if (xhci->irq >= 0) { */
-/*             free_irq(xhci->irq, xhci); */
-/*             xhci->irq = -1; */
-/*     } */
-
-/*         /\* Get the ring back from the backend domain.  Then free it.  Hmmmm. */
-/*          * Lets ignore this for now - not particularly useful. *\/ */
-
-/*     free_xhci(xhci); */
-/* } */
-
-/**
- * Initialise a new virtual root hub for a new USB device channel.
- */
-static int alloc_xhci(void)
-{
-       int retval;
-       struct usb_bus *bus;
-
-       retval = -EBUSY;
-
-       xhci = kmalloc(sizeof(*xhci), GFP_KERNEL);
-       if (!xhci) {
-               err("couldn't allocate xhci structure");
-               retval = -ENOMEM;
-               goto err_alloc_xhci;
-       }
-
-       /* Reset here so we don't get any interrupts from an old setup */
-       /*  or broken setup */
-       //      reset_hc(xhci);
-
-
-       xhci->state = USBIF_STATE_CLOSED;
-       xhci->is_suspended = 0;
-
-       spin_lock_init(&xhci->urb_remove_list_lock);
-       INIT_LIST_HEAD(&xhci->urb_remove_list);
-
-       spin_lock_init(&xhci->urb_list_lock);
-       INIT_LIST_HEAD(&xhci->urb_list);
-
-       spin_lock_init(&xhci->complete_list_lock);
-       INIT_LIST_HEAD(&xhci->complete_list);
-
-       spin_lock_init(&xhci->frame_list_lock);
-
-       /* We need exactly one page (per XHCI specs), how convenient */
-       /* We assume that one page is atleast 4k (1024 frames * 4 bytes) */
-#if PAGE_SIZE < (4 * 1024)
-#error PAGE_SIZE is not atleast 4k
-#endif
-       bus = usb_alloc_bus(&xhci_device_operations);
-       if (!bus) {
-               err("unable to allocate bus");
-               goto err_alloc_bus;
-       }
-
-       xhci->bus = bus;
-       bus->bus_name = "XHCI";
-       bus->hcpriv = xhci;
-
-       usb_register_bus(xhci->bus);
-
-       /* Initialize the root hub */
-
-       xhci->rh.numports = 0;
-
-       xhci->bus->root_hub = xhci->rh.dev = usb_alloc_dev(NULL, xhci->bus);
-       if (!xhci->rh.dev) {
-               err("unable to allocate root hub");
-               goto err_alloc_root_hub;
-       }
-
-       xhci->state = 0;
-
-       return 0;
-
-/*
- * error exits:
- */
-err_start_root_hub:
-       free_irq(xhci->irq, xhci);
-       xhci->irq = -1;
-
-err_alloc_root_hub:
-       usb_free_bus(xhci->bus);
-       xhci->bus = NULL;
-
-err_alloc_bus:
-       free_xhci(xhci);
-
-err_alloc_xhci:
-       return retval;
-}
-
-static void usbif_status_change(usbif_fe_interface_status_changed_t *status)
-{
-    ctrl_msg_t                   cmsg;
-    usbif_fe_interface_connect_t up;
-    long rc;
-    usbif_t *usbif;
-
-    switch ( status->status )
-    {
-    case USBIF_INTERFACE_STATUS_DESTROYED:
-        printk(KERN_WARNING "Unexpected usbif-DESTROYED message in state %d\n",
-               xhci->state);
-        break;
-
-    case USBIF_INTERFACE_STATUS_DISCONNECTED:
-        if ( xhci->state != USBIF_STATE_CLOSED )
-        {
-            printk(KERN_WARNING "Unexpected usbif-DISCONNECTED message"
-                   " in state %d\n", xhci->state);
-            break;
-            /* Not bothering to do recovery here for now.  Keep things
-             * simple. */
-        }
-
-        /* Move from CLOSED to DISCONNECTED state. */
-        xhci->usbif = usbif = (usbif_t *)__get_free_page(GFP_KERNEL);
-        usbif->req_prod = usbif->resp_prod = 0;
-        xhci->state  = USBIF_STATE_DISCONNECTED;
-
-        /* Construct an interface-CONNECT message for the domain controller. */
-        cmsg.type      = CMSG_USBIF_FE;
-        cmsg.subtype   = CMSG_USBIF_FE_INTERFACE_CONNECT;
-        cmsg.length    = sizeof(usbif_fe_interface_connect_t);
-        up.shmem_frame = virt_to_machine(usbif) >> PAGE_SHIFT;
-        memcpy(cmsg.msg, &up, sizeof(up));
-        
-        /* Tell the controller to bring up the interface. */
-        ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
-        break;
-
-    case USBIF_INTERFACE_STATUS_CONNECTED:
-        if ( xhci->state == USBIF_STATE_CLOSED )
-        {
-            printk(KERN_WARNING "Unexpected usbif-CONNECTED message"
-                   " in state %d\n", xhci->state);
-            break;
-        }
-
-        xhci->evtchn = status->evtchn;
-        xhci->irq = bind_evtchn_to_irq(xhci->evtchn);
-       xhci->bandwidth = status->bandwidth;
-       xhci->rh.numports = status->num_ports;
-
-        xhci->rh.ports = kmalloc (sizeof(xhci_port_t) * xhci->rh.numports, GFP_KERNEL);
-        memset(xhci->rh.ports, 0, sizeof(xhci_port_t) * xhci->rh.numports);
-
-        printk("rh.dev @ %p\n", xhci->rh.dev);
-
-       usb_connect(xhci->rh.dev);
-
-       if (usb_new_device(xhci->rh.dev) != 0) {
-               err("unable to start root hub");
-       }
-
-       /* Allocate the appropriate USB bandwidth here...  Need to
-       * somehow know what the total available is thought to be so we
-       * can calculate the reservation correctly. */
-       usb_claim_bandwidth(xhci->rh.dev, xhci->rh.urb,
-                           1000 - xhci->bandwidth, 0);
-
-        if ( (rc = request_irq(xhci->irq, xhci_interrupt, 
-                               SA_SAMPLE_RANDOM, "usbif", xhci)) )
-                printk(KERN_ALERT"usbfront request_irq failed (%ld)\n",rc);
-
-       printk(KERN_INFO __FILE__ ": USB XHCI: SHM at %p (0x%lx), EVTCHN %d IRQ %d\n",
-               xhci->usbif, virt_to_machine(xhci->usbif), xhci->evtchn, xhci->irq);
-
-        xhci->state = USBIF_STATE_CONNECTED;
-        
-        break;
-
-    default:
-        printk(KERN_WARNING "Status change to unknown value %d\n", 
-               status->status);
-        break;
-    }
-}
-
-
-static void usbif_ctrlif_rx(ctrl_msg_t *msg, unsigned long id)
-{
-    switch ( msg->subtype )
-    {
-    case CMSG_USBIF_FE_INTERFACE_STATUS_CHANGED:
-        if ( msg->length != sizeof(usbif_fe_interface_status_changed_t) )
-            goto parse_error;
-        usbif_status_change((usbif_fe_interface_status_changed_t *)
-                            &msg->msg[0]);
-        break;        
-
-        /* New interface...? */
-    default:
-        goto parse_error;
-    }
-
-    ctrl_if_send_response(msg);
-    return;
-
- parse_error:
-    msg->length = 0;
-    ctrl_if_send_response(msg);
-}
-
-
-static int __init xhci_hcd_init(void)
-{
-       int retval = -ENOMEM, i;
-        usbif_fe_interface_status_changed_t st;
-        control_msg_t cmsg;
-
-       if ( (xen_start_info.flags & SIF_INITDOMAIN)
-            || (xen_start_info.flags & SIF_USB_BE_DOMAIN) )
-                return 0;
-
-       info(DRIVER_DESC " " DRIVER_VERSION);
-
-       if (debug) {
-               errbuf = kmalloc(ERRBUF_LEN, GFP_KERNEL);
-               if (!errbuf)
-                       goto errbuf_failed;
-       }
-
-       xhci_up_cachep = kmem_cache_create("xhci_urb_priv",
-               sizeof(struct urb_priv), 0, 0, NULL, NULL);
-       if (!xhci_up_cachep)
-               goto up_failed;
-
-        /* Lazily avoid unloading issues for now. ;-)*/
-       MOD_INC_USE_COUNT;
-
-        /* Let the domain controller know we're here.  For now we wait until
-         * connection, as for the block and net drivers.  This is only strictly
-         * necessary if we're going to boot off a USB device. */
-        printk(KERN_INFO "Initialising Xen virtual USB hub\n");
-    
-        (void)ctrl_if_register_receiver(CMSG_USBIF_FE, usbif_ctrlif_rx,
-                                        CALLBACK_IN_BLOCKING_CONTEXT);
-        
-       alloc_xhci();
-
-        /* Send a driver-UP notification to the domain controller. */
-        cmsg.type      = CMSG_USBIF_FE;
-        cmsg.subtype   = CMSG_USBIF_FE_DRIVER_STATUS_CHANGED;
-        cmsg.length    = sizeof(usbif_fe_driver_status_changed_t);
-        st.status      = USBIF_DRIVER_STATUS_UP;
-        memcpy(cmsg.msg, &st, sizeof(st));
-        ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
-        
-        /*
-         * We should read 'nr_interfaces' from response message and wait
-         * for notifications before proceeding. For now we assume that we
-         * will be notified of exactly one interface.
-         */
-        for ( i=0; (xhci->state != USBIF_STATE_CONNECTED) && (i < 10*HZ); i++ )
-        {
-            set_current_state(TASK_INTERRUPTIBLE);
-            schedule_timeout(1);
-        }
-        
-        if (xhci->state != USBIF_STATE_CONNECTED)
-            printk(KERN_INFO "Timeout connecting USB frontend driver!\n");
-       
-       return 0;
-
-up_failed:
-
-       if (errbuf)
-               kfree(errbuf);
-
-errbuf_failed:
-
-       return retval;
-}
-
-static void __exit xhci_hcd_cleanup(void) 
-{
-       if (kmem_cache_destroy(xhci_up_cachep))
-               printk(KERN_INFO "xhci: not all urb_priv's were freed\n");
-
-//        release_xhci(); do some calls here
-
-
-       if (errbuf)
-               kfree(errbuf);
-}
-
-module_init(xhci_hcd_init);
-module_exit(xhci_hcd_cleanup);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-
diff --git a/linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/frontend/xhci.h b/linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/frontend/xhci.h
deleted file mode 100644 (file)
index 4be67b9..0000000
+++ /dev/null
@@ -1,210 +0,0 @@
-#ifndef __LINUX_XHCI_H
-#define __LINUX_XHCI_H
-
-#include <linux/list.h>
-#include <linux/usb.h>
-#include "../usbif.h"
-#include <linux/spinlock.h>
-
-#define XHCI_NUMFRAMES         1024    /* in the frame list [array] */
-#define XHCI_MAX_SOF_NUMBER    2047    /* in an SOF packet */
-#define CAN_SCHEDULE_FRAMES    1000    /* how far future frames can be scheduled */
-
-/* In the absence of actual hardware state, we maintain the current known state
- * of the virtual hub ports in this data structure.
- */
-typedef struct
-{
-        unsigned int cs     :1;     /* Connection status.  do we really need this /and/ ccs? */
-        unsigned int cs_chg :1; /* Connection status change.  */
-        unsigned int pe     :1;     /* Port enable.               */
-        unsigned int pe_chg :1; /* Port enable change.        */
-        unsigned int ccs    :1;    /* Current connect status.    */
-        unsigned int susp   :1;   /* Suspended.                 */
-        unsigned int lsda   :1;   /* Low speed device attached. */
-        unsigned int pr     :1;     /* Port reset.                */
-        
-    /* Device info? */
-} xhci_port_t;
-
-struct xhci_frame_list {
-       __u32 frame[XHCI_NUMFRAMES];
-
-       void *frame_cpu[XHCI_NUMFRAMES];
-};
-
-struct urb_priv;
-
-#define xhci_status_bits(ctrl_sts)     (ctrl_sts & 0xFE0000)
-#define xhci_actual_length(ctrl_sts)   ((ctrl_sts + 1) & TD_CTRL_ACTLEN_MASK) /* 1-based */
-
-#define xhci_maxlen(token)     ((token) >> 21)
-#define xhci_expected_length(info) (((info >> 21) + 1) & TD_TOKEN_EXPLEN_MASK) /* 1-based */
-#define xhci_toggle(token)     (((token) >> TD_TOKEN_TOGGLE_SHIFT) & 1)
-#define xhci_endpoint(token)   (((token) >> 15) & 0xf)
-#define xhci_devaddr(token)    (((token) >> 8) & 0x7f)
-#define xhci_devep(token)      (((token) >> 8) & 0x7ff)
-#define xhci_packetid(token)   ((token) & TD_TOKEN_PID_MASK)
-#define xhci_packetout(token)  (xhci_packetid(token) != USB_PID_IN)
-#define xhci_packetin(token)   (xhci_packetid(token) == USB_PID_IN)
-
-struct virt_root_hub {
-       struct usb_device *dev;
-       int devnum;             /* Address of Root Hub endpoint */
-       struct urb *urb;
-       void *int_addr;
-       int send;
-       int interval;
-       int numports;
-       int c_p_r[8];
-       struct timer_list rh_int_timer;
-        spinlock_t port_state_lock;
-        xhci_port_t *ports;       /*  */
-};
-
-/*
- * This describes the full xhci information.
- *
- * Note how the "proper" USB information is just
- * a subset of what the full implementation needs.
- */
-struct xhci {
-
-#ifdef CONFIG_PROC_FS
-       /* procfs */
-       int num;
-       struct proc_dir_entry *proc_entry;
-#endif
-
-        int evtchn;                        /* Interdom channel to backend */
-        int irq;                           /* Bound to evtchn */
-        int state;                         /* State of this USB interface */
-        unsigned long bandwidth;
-        int handle;
-
-       struct usb_bus *bus;
-
-       spinlock_t frame_list_lock;
-       struct xhci_frame_list *fl;             /* P: xhci->frame_list_lock */
-       int is_suspended;
-
-       /* Main list of URB's currently controlled by this HC */
-       spinlock_t urb_list_lock;
-       struct list_head urb_list;              /* P: xhci->urb_list_lock */
-
-       /* List of asynchronously unlinked URB's */
-       spinlock_t urb_remove_list_lock;
-       struct list_head urb_remove_list;       /* P: xhci->urb_remove_list_lock */
-
-       /* List of URB's awaiting completion callback */
-       spinlock_t complete_list_lock;
-       struct list_head complete_list;         /* P: xhci->complete_list_lock */
-
-       struct virt_root_hub rh;        /* private data of the virtual root hub */
-
-        spinlock_t response_lock;
-
-        usbif_t *usbif;
-        int usb_resp_cons;
-};
-
-struct urb_priv {
-       struct urb *urb;
-        usbif_iso_t *schedule;
-       struct usb_device *dev;
-
-        int in_progress : 1;           /* QH was queued (not linked in) */
-       int short_control_packet : 1;   /* If we get a short packet during */
-                                       /*  a control transfer, retrigger */
-                                       /*  the status phase */
-
-       int status;                     /* Final status */
-
-       unsigned long inserttime;       /* In jiffies */
-
-       struct list_head queue_list;    /* P: xhci->frame_list_lock */
-       struct list_head complete_list; /* P: xhci->complete_list_lock */
-};
-
-/*
- * Locking in xhci.c
- *
- * spinlocks are used extensively to protect the many lists and data
- * structures we have. It's not that pretty, but it's necessary. We
- * need to be done with all of the locks (except complete_list_lock) when
- * we call urb->complete. I've tried to make it simple enough so I don't
- * have to spend hours racking my brain trying to figure out if the
- * locking is safe.
- *
- * Here's the safe locking order to prevent deadlocks:
- *
- * #1 xhci->urb_list_lock
- * #2 urb->lock
- * #3 xhci->urb_remove_list_lock, xhci->frame_list_lock, 
- *   xhci->qh_remove_list_lock
- * #4 xhci->complete_list_lock
- *
- * If you're going to grab 2 or more locks at once, ALWAYS grab the lock
- * at the lowest level FIRST and NEVER grab locks at the same level at the
- * same time.
- * 
- * So, if you need xhci->urb_list_lock, grab it before you grab urb->lock
- */
-
-/* -------------------------------------------------------------------------
-   Virtual Root HUB
-   ------------------------------------------------------------------------- */
-/* destination of request */
-#define RH_DEVICE              0x00
-#define RH_INTERFACE           0x01
-#define RH_ENDPOINT            0x02
-#define RH_OTHER               0x03
-
-#define RH_CLASS               0x20
-#define RH_VENDOR              0x40
-
-/* Requests: bRequest << 8 | bmRequestType */
-#define RH_GET_STATUS          0x0080
-#define RH_CLEAR_FEATURE       0x0100
-#define RH_SET_FEATURE         0x0300
-#define RH_SET_ADDRESS         0x0500
-#define RH_GET_DESCRIPTOR      0x0680
-#define RH_SET_DESCRIPTOR      0x0700
-#define RH_GET_CONFIGURATION   0x0880
-#define RH_SET_CONFIGURATION   0x0900
-#define RH_GET_STATE           0x0280
-#define RH_GET_INTERFACE       0x0A80
-#define RH_SET_INTERFACE       0x0B00
-#define RH_SYNC_FRAME          0x0C80
-/* Our Vendor Specific Request */
-#define RH_SET_EP              0x2000
-
-/* Hub port features */
-#define RH_PORT_CONNECTION     0x00
-#define RH_PORT_ENABLE         0x01
-#define RH_PORT_SUSPEND                0x02
-#define RH_PORT_OVER_CURRENT   0x03
-#define RH_PORT_RESET          0x04
-#define RH_PORT_POWER          0x08
-#define RH_PORT_LOW_SPEED      0x09
-#define RH_C_PORT_CONNECTION   0x10
-#define RH_C_PORT_ENABLE       0x11
-#define RH_C_PORT_SUSPEND      0x12
-#define RH_C_PORT_OVER_CURRENT 0x13
-#define RH_C_PORT_RESET                0x14
-
-/* Hub features */
-#define RH_C_HUB_LOCAL_POWER   0x00
-#define RH_C_HUB_OVER_CURRENT  0x01
-#define RH_DEVICE_REMOTE_WAKEUP        0x00
-#define RH_ENDPOINT_STALL      0x01
-
-/* Our Vendor Specific feature */
-#define RH_REMOVE_EP           0x00
-
-#define RH_ACK                 0x01
-#define RH_REQ_ERR             -1
-#define RH_NACK                        0x00
-
-#endif
-
diff --git a/linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/usbif.h b/linux-2.4.28-xen-sparse/arch/xen/drivers/usbif/usbif.h
deleted file mode 100644 (file)
index 11cea15..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-/******************************************************************************
- * usbif.h
- * 
- * Unified block-device I/O interface for Xen guest OSes.
- * 
- * Copyright (c) 2003-2004, Keir Fraser
- */
-
-#ifndef __SHARED_USBIF_H__
-#define __SHARED_USBIF_H__
-
-#define usbif_vdev_t   u16
-#define usbif_sector_t u64
-
-#define USBIF_OP_IO      0
-#define USBIF_OP_PROBE   1 /* Is there a device on this port? */
-#define USBIF_OP_RESET   2 /* Reset a virtual USB port.       */
-
-/* NB. Ring size must be small enough for sizeof(usbif_ring_t) <= PAGE_SIZE. */
-#define USBIF_RING_SIZE        64
-
-/* XXX this does not want to be here!  it really ought to be dynamic but it can
- * live here for now */
-#define NUM_PORTS 1
-
-typedef struct {
-    unsigned long  id;           /*  0: private guest value, echoed in resp  */
-    u8             operation;    /*  4: USBIF_OP_???                         */
-    u8  __pad1;
-    usbif_vdev_t   port;         /* 6 : guest virtual USB port               */
-    unsigned long  devnum :7;    /* 8 : Device address, as seen by the guest.*/
-    unsigned long  endpoint :4;  /* Device endpoint.                         */
-    unsigned long  direction :1; /* Pipe direction.                          */
-    unsigned long  speed :1;     /* Pipe speed.                              */
-    unsigned long  pipe_type :2; /* Pipe type (iso, bulk, int, ctrl)         */
-    unsigned long  __pad2 :18;
-    unsigned long  transfer_buffer; /* 12: Machine address */
-    unsigned long  length;          /* 16: Buffer length */
-    unsigned long  transfer_flags;  /* 20: For now just pass Linux transfer
-                                     * flags - this may change. */
-    unsigned char setup[8];         /* 22 Embed setup packets directly. */
-    unsigned long  iso_schedule;    /* 30 Machine address of transfer sched (iso
-                                     * only) */
-    unsigned long num_iso;        /* 34 : length of iso schedule */
-    unsigned long timeout;        /* 38: timeout in ms */
-} PACKED usbif_request_t; /* 42 */
-/* Data we need to pass:
- * - Transparently handle short packets or complain at us?
- */
-
-typedef struct {
-    unsigned long   id;              /* 0: copied from request         */
-    u8              operation;       /* 4: copied from request         */
-    u8              data;            /* 5: Small chunk of in-band data */
-    s16             status;          /* 6: USBIF_RSP_???               */
-    unsigned long   transfer_mutex;  /* Used for cancelling requests atomically. */
-    unsigned long    length;          /* 8: How much data we really got */
-} PACKED usbif_response_t;
-
-#define USBIF_RSP_ERROR  -1 /* non-specific 'error' */
-#define USBIF_RSP_OKAY    0 /* non-specific 'okay'  */
-
-/*
- * We use a special capitalised type name because it is _essential_ that all 
- * arithmetic on indexes is done on an integer type of the correct size.
- */
-typedef u32 USBIF_RING_IDX;
-
-/*
- * Ring indexes are 'free running'. That is, they are not stored modulo the
- * size of the ring buffer. The following macro converts a free-running counter
- * into a value that can directly index a ring-buffer array.
- */
-#define MASK_USBIF_IDX(_i) ((_i)&(USBIF_RING_SIZE-1))
-
-typedef struct {
-    USBIF_RING_IDX req_prod;  /*  0: Request producer. Updated by front-end. */
-    USBIF_RING_IDX resp_prod; /*  4: Response producer. Updated by back-end. */
-
-    union {                   /*  8 */
-        usbif_request_t  req;
-        usbif_response_t resp;
-    } PACKED ring[USBIF_RING_SIZE];
-} PACKED usbif_t;
-
-
-
-/*
- * USBIF_OP_PROBE:
- * The request format for a probe request is constrained as follows:
- *  @operation   == USBIF_OP_PROBE
- *  @nr_segments == size of probe buffer in pages
- *  @device      == unused (zero)
- *  @id          == any value (echoed in response message)
- *  @sector_num  == unused (zero)
- *  @frame_and_sects == list of page-sized buffers.
- *                       (i.e., @first_sect == 0, @last_sect == 7).
- * 
- * The response is a list of vdisk_t elements copied into the out-of-band
- * probe buffer. On success the response status field contains the number
- * of vdisk_t elements.
- */
-
-typedef struct {
-    unsigned long length; /* IN = expected, OUT = actual */
-    unsigned long buffer_offset;  /* IN offset in buffer specified in main
-                                     packet */
-    unsigned long status; /* OUT Status for this packet. */
-} usbif_iso_t;
-
-#endif /* __SHARED_USBIF_H__ */
diff --git a/linux-2.4.28-xen-sparse/drivers/usb/hcd.c b/linux-2.4.28-xen-sparse/drivers/usb/hcd.c
deleted file mode 100644 (file)
index 6ea4a55..0000000
+++ /dev/null
@@ -1,1511 +0,0 @@
-/*
- * Copyright (c) 2001-2002 by David Brownell
- * 
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/smp_lock.h>
-#include <linux/errno.h>
-#include <linux/kmod.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/list.h>
-#include <linux/interrupt.h>
-#include <linux/completion.h>
-#include <linux/uts.h>                 /* for UTS_SYSNAME */
-
-
-#ifdef CONFIG_USB_DEBUG
-       #define DEBUG
-#else
-       #undef DEBUG
-#endif
-
-#include <linux/usb.h>
-#include "hcd.h"
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/unaligned.h>
-
-
-/*-------------------------------------------------------------------------*/
-
-/*
- * USB Host Controller Driver framework
- *
- * Plugs into usbcore (usb_bus) and lets HCDs share code, minimizing
- * HCD-specific behaviors/bugs.  Think of it as the "upper level" of
- * some drivers, where the "lower level" is hardware-specific.
- *
- * This does error checks, tracks devices and urbs, and delegates to a
- * "hc_driver" only for code (and data) that really needs to know about
- * hardware differences.  That includes root hub registers, i/o queues,
- * and so on ... but as little else as possible.
- *
- * Shared code includes most of the "root hub" code (these are emulated,
- * though each HC's hardware works differently) and PCI glue, plus request
- * tracking overhead.  The HCD code should only block on spinlocks or on
- * hardware handshaking; blocking on software events (such as other kernel
- * threads releasing resources, or completing actions) is all generic.
- *
- * Happens the USB 2.0 spec says this would be invisible inside the "USBD",
- * and includes mostly a "HCDI" (HCD Interface) along with some APIs used
- * only by the hub driver ... and that neither should be seen or used by
- * usb client device drivers.
- *
- * Contributors of ideas or unattributed patches include: David Brownell,
- * Roman Weissgaerber, Rory Bolt, ...
- *
- * HISTORY:
- * 2002-sept   Merge some 2.5 updates so we can share hardware level HCD
- *     code between the 2.4.20+ and 2.5 trees.
- * 2002-feb    merge to 2.4.19
- * 2001-12-12  Initial patch version for Linux 2.5.1 kernel.
- */
-
-/*-------------------------------------------------------------------------*/
-
-/* host controllers we manage */
-static LIST_HEAD (hcd_list);
-
-/* used when updating list of hcds */
-static DECLARE_MUTEX (hcd_list_lock);
-
-/* used when updating hcd data */
-static spinlock_t hcd_data_lock = SPIN_LOCK_UNLOCKED;
-
-static struct usb_operations hcd_operations;
-
-/*-------------------------------------------------------------------------*/
-
-/*
- * Sharable chunks of root hub code.
- */
-
-/*-------------------------------------------------------------------------*/
-
-#define KERNEL_REL     ((LINUX_VERSION_CODE >> 16) & 0x0ff)
-#define KERNEL_VER     ((LINUX_VERSION_CODE >> 8) & 0x0ff)
-
-/* usb 2.0 root hub device descriptor */
-static const u8 usb2_rh_dev_descriptor [18] = {
-       0x12,       /*  __u8  bLength; */
-       0x01,       /*  __u8  bDescriptorType; Device */
-       0x00, 0x02, /*  __u16 bcdUSB; v2.0 */
-
-       0x09,       /*  __u8  bDeviceClass; HUB_CLASSCODE */
-       0x00,       /*  __u8  bDeviceSubClass; */
-       0x01,       /*  __u8  bDeviceProtocol; [ usb 2.0 single TT ]*/
-       0x08,       /*  __u8  bMaxPacketSize0; 8 Bytes */
-
-       0x00, 0x00, /*  __u16 idVendor; */
-       0x00, 0x00, /*  __u16 idProduct; */
-       KERNEL_VER, KERNEL_REL, /*  __u16 bcdDevice */
-
-       0x03,       /*  __u8  iManufacturer; */
-       0x02,       /*  __u8  iProduct; */
-       0x01,       /*  __u8  iSerialNumber; */
-       0x01        /*  __u8  bNumConfigurations; */
-};
-
-/* no usb 2.0 root hub "device qualifier" descriptor: one speed only */
-
-/* usb 1.1 root hub device descriptor */
-static const u8 usb11_rh_dev_descriptor [18] = {
-       0x12,       /*  __u8  bLength; */
-       0x01,       /*  __u8  bDescriptorType; Device */
-       0x10, 0x01, /*  __u16 bcdUSB; v1.1 */
-
-       0x09,       /*  __u8  bDeviceClass; HUB_CLASSCODE */
-       0x00,       /*  __u8  bDeviceSubClass; */
-       0x00,       /*  __u8  bDeviceProtocol; [ low/full speeds only ] */
-       0x08,       /*  __u8  bMaxPacketSize0; 8 Bytes */
-
-       0x00, 0x00, /*  __u16 idVendor; */
-       0x00, 0x00, /*  __u16 idProduct; */
-       KERNEL_VER, KERNEL_REL, /*  __u16 bcdDevice */
-
-       0x03,       /*  __u8  iManufacturer; */
-       0x02,       /*  __u8  iProduct; */
-       0x01,       /*  __u8  iSerialNumber; */
-       0x01        /*  __u8  bNumConfigurations; */
-};
-
-
-/*-------------------------------------------------------------------------*/
-
-/* Configuration descriptors for our root hubs */
-
-static const u8 fs_rh_config_descriptor [] = {
-
-       /* one configuration */
-       0x09,       /*  __u8  bLength; */
-       0x02,       /*  __u8  bDescriptorType; Configuration */
-       0x19, 0x00, /*  __u16 wTotalLength; */
-       0x01,       /*  __u8  bNumInterfaces; (1) */
-       0x01,       /*  __u8  bConfigurationValue; */
-       0x00,       /*  __u8  iConfiguration; */
-       0x40,       /*  __u8  bmAttributes; 
-                                Bit 7: Bus-powered,
-                                    6: Self-powered,
-                                    5 Remote-wakwup,
-                                    4..0: resvd */
-       0x00,       /*  __u8  MaxPower; */
-      
-       /* USB 1.1:
-        * USB 2.0, single TT organization (mandatory):
-        *      one interface, protocol 0
-        *
-        * USB 2.0, multiple TT organization (optional):
-        *      two interfaces, protocols 1 (like single TT)
-        *      and 2 (multiple TT mode) ... config is
-        *      sometimes settable
-        *      NOT IMPLEMENTED
-        */
-
-       /* one interface */
-       0x09,       /*  __u8  if_bLength; */
-       0x04,       /*  __u8  if_bDescriptorType; Interface */
-       0x00,       /*  __u8  if_bInterfaceNumber; */
-       0x00,       /*  __u8  if_bAlternateSetting; */
-       0x01,       /*  __u8  if_bNumEndpoints; */
-       0x09,       /*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
-       0x00,       /*  __u8  if_bInterfaceSubClass; */
-       0x00,       /*  __u8  if_bInterfaceProtocol; [usb1.1 or single tt] */
-       0x00,       /*  __u8  if_iInterface; */
-     
-       /* one endpoint (status change endpoint) */
-       0x07,       /*  __u8  ep_bLength; */
-       0x05,       /*  __u8  ep_bDescriptorType; Endpoint */
-       0x81,       /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
-       0x03,       /*  __u8  ep_bmAttributes; Interrupt */
-       0x02, 0x00, /*  __u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */
-       0xff        /*  __u8  ep_bInterval; (255ms -- usb 2.0 spec) */
-};
-
-static const u8 hs_rh_config_descriptor [] = {
-
-       /* one configuration */
-       0x09,       /*  __u8  bLength; */
-       0x02,       /*  __u8  bDescriptorType; Configuration */
-       0x19, 0x00, /*  __u16 wTotalLength; */
-       0x01,       /*  __u8  bNumInterfaces; (1) */
-       0x01,       /*  __u8  bConfigurationValue; */
-       0x00,       /*  __u8  iConfiguration; */
-       0x40,       /*  __u8  bmAttributes; 
-                                Bit 7: Bus-powered,
-                                    6: Self-powered,
-                                    5 Remote-wakwup,
-                                    4..0: resvd */
-       0x00,       /*  __u8  MaxPower; */
-      
-       /* USB 1.1:
-        * USB 2.0, single TT organization (mandatory):
-        *      one interface, protocol 0
-        *
-        * USB 2.0, multiple TT organization (optional):
-        *      two interfaces, protocols 1 (like single TT)
-        *      and 2 (multiple TT mode) ... config is
-        *      sometimes settable
-        *      NOT IMPLEMENTED
-        */
-
-       /* one interface */
-       0x09,       /*  __u8  if_bLength; */
-       0x04,       /*  __u8  if_bDescriptorType; Interface */
-       0x00,       /*  __u8  if_bInterfaceNumber; */
-       0x00,       /*  __u8  if_bAlternateSetting; */
-       0x01,       /*  __u8  if_bNumEndpoints; */
-       0x09,       /*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
-       0x00,       /*  __u8  if_bInterfaceSubClass; */
-       0x00,       /*  __u8  if_bInterfaceProtocol; [usb1.1 or single tt] */
-       0x00,       /*  __u8  if_iInterface; */
-     
-       /* one endpoint (status change endpoint) */
-       0x07,       /*  __u8  ep_bLength; */
-       0x05,       /*  __u8  ep_bDescriptorType; Endpoint */
-       0x81,       /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
-       0x03,       /*  __u8  ep_bmAttributes; Interrupt */
-       0x02, 0x00, /*  __u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */
-       0x0c        /*  __u8  ep_bInterval; (256ms -- usb 2.0 spec) */
-};
-
-/*-------------------------------------------------------------------------*/
-
-/*
- * helper routine for returning string descriptors in UTF-16LE
- * input can actually be ISO-8859-1; ASCII is its 7-bit subset
- */
-static int ascii2utf (char *s, u8 *utf, int utfmax)
-{
-       int retval;
-
-       for (retval = 0; *s && utfmax > 1; utfmax -= 2, retval += 2) {
-               *utf++ = *s++;
-               *utf++ = 0;
-       }
-       return retval;
-}
-
-/*
- * rh_string - provides manufacturer, product and serial strings for root hub
- * @id: the string ID number (1: serial number, 2: product, 3: vendor)
- * @pci_desc: PCI device descriptor for the relevant HC
- * @type: string describing our driver 
- * @data: return packet in UTF-16 LE
- * @len: length of the return packet
- *
- * Produces either a manufacturer, product or serial number string for the
- * virtual root hub device.
- */
-static int rh_string (
-       int             id,
-       struct usb_hcd  *hcd,
-       u8              *data,
-       int             len
-) {
-       char buf [100];
-
-       // language ids
-       if (id == 0) {
-               *data++ = 4; *data++ = 3;       /* 4 bytes string data */
-               *data++ = 0; *data++ = 0;       /* some language id */
-               return 4;
-
-       // serial number
-       } else if (id == 1) {
-               strcpy (buf, hcd->bus->bus_name);
-
-       // product description
-       } else if (id == 2) {
-                strcpy (buf, hcd->product_desc);
-
-       // id 3 == vendor description
-       } else if (id == 3) {
-                sprintf (buf, "%s %s %s", UTS_SYSNAME, UTS_RELEASE,
-                       hcd->description);
-
-       // unsupported IDs --> "protocol stall"
-       } else
-           return 0;
-
-       data [0] = 2 * (strlen (buf) + 1);
-       data [1] = 3;   /* type == string */
-       return 2 + ascii2utf (buf, data + 2, len - 2);
-}
-
-
-/* Root hub control transfers execute synchronously */
-static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
-{
-       struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *) urb->setup_packet;
-       u16             typeReq, wValue, wIndex, wLength;
-       const u8        *bufp = 0;
-       u8              *ubuf = urb->transfer_buffer;
-       int             len = 0;
-
-       typeReq  = (cmd->bRequestType << 8) | cmd->bRequest;
-       wValue   = le16_to_cpu (cmd->wValue);
-       wIndex   = le16_to_cpu (cmd->wIndex);
-       wLength  = le16_to_cpu (cmd->wLength);
-
-       if (wLength > urb->transfer_buffer_length)
-               goto error;
-
-       /* set up for success */
-       urb->status = 0;
-       urb->actual_length = wLength;
-       switch (typeReq) {
-
-       /* DEVICE REQUESTS */
-
-       case DeviceRequest | USB_REQ_GET_STATUS:
-               // DEVICE_REMOTE_WAKEUP
-               ubuf [0] = 1; // selfpowered
-               ubuf [1] = 0;
-                       /* FALLTHROUGH */
-       case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
-       case DeviceOutRequest | USB_REQ_SET_FEATURE:
-               dbg ("no device features yet yet");
-               break;
-       case DeviceRequest | USB_REQ_GET_CONFIGURATION:
-               ubuf [0] = 1;
-                       /* FALLTHROUGH */
-       case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
-               break;
-       case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
-               switch (wValue & 0xff00) {
-               case USB_DT_DEVICE << 8:
-                       if (hcd->driver->flags & HCD_USB2)
-                               bufp = usb2_rh_dev_descriptor;
-                       else if (hcd->driver->flags & HCD_USB11)
-                               bufp = usb11_rh_dev_descriptor;
-                       else
-                               goto error;
-                       len = 18;
-                       break;
-               case USB_DT_CONFIG << 8:
-                       if (hcd->driver->flags & HCD_USB2) {
-                               bufp = hs_rh_config_descriptor;
-                               len = sizeof hs_rh_config_descriptor;
-                       } else {
-                               bufp = fs_rh_config_descriptor;
-                               len = sizeof fs_rh_config_descriptor;
-                       }
-                       break;
-               case USB_DT_STRING << 8:
-                       urb->actual_length = rh_string (
-                               wValue & 0xff, hcd,
-                               ubuf, wLength);
-                       break;
-               default:
-                       goto error;
-               }
-               break;
-       case DeviceRequest | USB_REQ_GET_INTERFACE:
-               ubuf [0] = 0;
-                       /* FALLTHROUGH */
-       case DeviceOutRequest | USB_REQ_SET_INTERFACE:
-               break;
-       case DeviceOutRequest | USB_REQ_SET_ADDRESS:
-               // wValue == urb->dev->devaddr
-               dbg ("%s root hub device address %d",
-                       hcd->bus->bus_name, wValue);
-               break;
-
-       /* INTERFACE REQUESTS (no defined feature/status flags) */
-
-       /* ENDPOINT REQUESTS */
-
-       case EndpointRequest | USB_REQ_GET_STATUS:
-               // ENDPOINT_HALT flag
-               ubuf [0] = 0;
-               ubuf [1] = 0;
-                       /* FALLTHROUGH */
-       case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
-       case EndpointOutRequest | USB_REQ_SET_FEATURE:
-               dbg ("no endpoint features yet");
-               break;
-
-       /* CLASS REQUESTS (and errors) */
-
-       default:
-               /* non-generic request */
-               urb->status = hcd->driver->hub_control (hcd,
-                       typeReq, wValue, wIndex,
-                       ubuf, wLength);
-               break;
-error:
-               /* "protocol stall" on error */
-               urb->status = -EPIPE;
-               dbg ("unsupported hub control message (maxchild %d)",
-                               urb->dev->maxchild);
-       }
-       if (urb->status) {
-               urb->actual_length = 0;
-               dbg ("CTRL: TypeReq=0x%x val=0x%x idx=0x%x len=%d ==> %d",
-                       typeReq, wValue, wIndex, wLength, urb->status);
-       }
-       if (bufp) {
-               if (urb->transfer_buffer_length < len)
-                       len = urb->transfer_buffer_length;
-               urb->actual_length = len;
-               // always USB_DIR_IN, toward host
-               memcpy (ubuf, bufp, len);
-       }
-
-       /* any errors get returned through the urb completion */
-       usb_hcd_giveback_urb (hcd, urb, 0);
-       return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/*
- * Root Hub interrupt transfers are synthesized with a timer.
- * Completions are called in_interrupt() but not in_irq().
- */
-
-static void rh_report_status (unsigned long ptr);
-
-static int rh_status_urb (struct usb_hcd *hcd, struct urb *urb) 
-{
-       int     len = 1 + (urb->dev->maxchild / 8);
-
-       /* rh_timer protected by hcd_data_lock */
-       if (timer_pending (&hcd->rh_timer)
-                       || urb->status != -EINPROGRESS
-                       || !HCD_IS_RUNNING (hcd->state)
-                       || urb->transfer_buffer_length < len) {
-               dbg ("not queuing status urb, stat %d", urb->status);
-               return -EINVAL;
-       }
-
-       urb->hcpriv = hcd;      /* nonzero to indicate it's queued */
-       init_timer (&hcd->rh_timer);
-       hcd->rh_timer.function = rh_report_status;
-       hcd->rh_timer.data = (unsigned long) urb;
-       /* USB 2.0 spec says 256msec; this is close enough */
-       hcd->rh_timer.expires = jiffies + HZ/4;
-       add_timer (&hcd->rh_timer);
-       return 0;
-}
-
-/* timer callback */
-
-static void rh_report_status (unsigned long ptr)
-{
-       struct urb      *urb;
-       struct usb_hcd  *hcd;
-       int             length;
-       unsigned long   flags;
-
-       urb = (struct urb *) ptr;
-       spin_lock_irqsave (&urb->lock, flags);
-       if (!urb->dev) {
-               spin_unlock_irqrestore (&urb->lock, flags);
-               return;
-       }
-
-       hcd = urb->dev->bus->hcpriv;
-       if (urb->status == -EINPROGRESS) {
-               if (HCD_IS_RUNNING (hcd->state)) {
-                       length = hcd->driver->hub_status_data (hcd,
-                                       urb->transfer_buffer);
-                       spin_unlock_irqrestore (&urb->lock, flags);
-                       if (length > 0) {
-                               urb->actual_length = length;
-                               urb->status = 0;
-                               urb->complete (urb);
-                       }
-                       spin_lock_irqsave (&hcd_data_lock, flags);
-                       urb->status = -EINPROGRESS;
-                       if (HCD_IS_RUNNING (hcd->state)
-                                       && rh_status_urb (hcd, urb) != 0) {
-                               /* another driver snuck in? */
-                               dbg ("%s, can't resubmit roothub status urb?",
-                                       hcd->bus->bus_name);
-                               spin_unlock_irqrestore (&hcd_data_lock, flags);
-                               BUG ();
-                       }
-                       spin_unlock_irqrestore (&hcd_data_lock, flags);
-               } else
-                       spin_unlock_irqrestore (&urb->lock, flags);
-       } else {
-               /* this urb's been unlinked */
-               urb->hcpriv = 0;
-               spin_unlock_irqrestore (&urb->lock, flags);
-
-               usb_hcd_giveback_urb (hcd, urb, 0);
-       }
-}
-
-/*-------------------------------------------------------------------------*/
-
-static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb)
-{
-       if (usb_pipeint (urb->pipe)) {
-               int             retval;
-               unsigned long   flags;
-
-               spin_lock_irqsave (&hcd_data_lock, flags);
-               retval = rh_status_urb (hcd, urb);
-               spin_unlock_irqrestore (&hcd_data_lock, flags);
-               return retval;
-       }
-       if (usb_pipecontrol (urb->pipe))
-               return rh_call_control (hcd, urb);
-       else
-               return -EINVAL;
-}
-
-/*-------------------------------------------------------------------------*/
-
-static void rh_status_dequeue (struct usb_hcd *hcd, struct urb *urb)
-{
-       unsigned long   flags;
-
-       spin_lock_irqsave (&hcd_data_lock, flags);
-       del_timer_sync (&hcd->rh_timer);
-       hcd->rh_timer.data = 0;
-       spin_unlock_irqrestore (&hcd_data_lock, flags);
-
-       /* we rely on RH callback code not unlinking its URB! */
-       usb_hcd_giveback_urb (hcd, urb, 0);
-}
-
-/*-------------------------------------------------------------------------*/
-
-#ifdef CONFIG_PCI
-
-/* PCI-based HCs are normal, but custom bus glue should be ok */
-
-static void hcd_irq (int irq, void *__hcd, struct pt_regs *r);
-static void hc_died (struct usb_hcd *hcd);
-
-/*-------------------------------------------------------------------------*/
-
-/* configure so an HC device and id are always provided */
-/* always called with process context; sleeping is OK */
-
-/**
- * usb_hcd_pci_probe - initialize PCI-based HCDs
- * @dev: USB Host Controller being probed
- * @id: pci hotplug id connecting controller to HCD framework
- * Context: !in_interrupt()
- *
- * Allocates basic PCI resources for this USB host controller, and
- * then invokes the start() method for the HCD associated with it
- * through the hotplug entry's driver_data.
- *
- * Store this function in the HCD's struct pci_driver as probe().
- */
-int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
-{
-       struct hc_driver        *driver;
-       unsigned long           resource, len;
-       void                    *base;
-       struct usb_bus          *bus;
-       struct usb_hcd          *hcd;
-       int                     retval, region;
-       char                    buf [8], *bufp = buf;
-
-       if (!id || !(driver = (struct hc_driver *) id->driver_data))
-               return -EINVAL;
-
-       if (pci_enable_device (dev) < 0)
-               return -ENODEV;
-       
-        if (!dev->irq) {
-               err ("Found HC with no IRQ.  Check BIOS/PCI %s setup!",
-                       dev->slot_name);
-               return -ENODEV;
-        }
-       
-       if (driver->flags & HCD_MEMORY) {       // EHCI, OHCI
-               region = 0;
-               resource = pci_resource_start (dev, 0);
-               len = pci_resource_len (dev, 0);
-               if (!request_mem_region (resource, len, driver->description)) {
-                       dbg ("controller already in use");
-                       return -EBUSY;
-               }
-               base = ioremap_nocache (resource, len);
-               if (base == NULL) {
-                       dbg ("error mapping memory");
-                       retval = -EFAULT;
-clean_1:
-                       release_mem_region (resource, len);
-                       err ("init %s fail, %d", dev->slot_name, retval);
-                       return retval;
-               }
-
-       } else {                                // UHCI
-               resource = len = 0;
-               for (region = 0; region < PCI_ROM_RESOURCE; region++) {
-                       if (!(pci_resource_flags (dev, region) & IORESOURCE_IO))
-                               continue;
-
-                       resource = pci_resource_start (dev, region);
-                       len = pci_resource_len (dev, region);
-                       if (request_region (resource, len,
-                                       driver->description))
-                               break;
-               }
-               if (region == PCI_ROM_RESOURCE) {
-                       dbg ("no i/o regions available");
-                       return -EBUSY;
-               }
-               base = (void *) resource;
-       }
-
-       // driver->start(), later on, will transfer device from
-       // control by SMM/BIOS to control by Linux (if needed)
-
-       pci_set_master (dev);
-       hcd = driver->hcd_alloc ();
-       if (hcd == NULL){
-               dbg ("hcd alloc fail");
-               retval = -ENOMEM;
-clean_2:
-               if (driver->flags & HCD_MEMORY) {
-                       iounmap (base);
-                       goto clean_1;
-               } else {
-                       release_region (resource, len);
-                       err ("init %s fail, %d", dev->slot_name, retval);
-                       return retval;
-               }
-       }
-       pci_set_drvdata(dev, hcd);
-       hcd->driver = driver;
-       hcd->description = driver->description;
-       hcd->pdev = dev;
-       printk (KERN_INFO "%s %s: %s\n",
-                       hcd->description,  dev->slot_name, dev->name);
-
-#ifndef __sparc__
-       sprintf (buf, "%d", dev->irq);
-#else
-       bufp = __irq_itoa(dev->irq);
-#endif
-       if (request_irq (dev->irq, hcd_irq, SA_SHIRQ, hcd->description, hcd)
-                       != 0) {
-               err ("request interrupt %s failed", bufp);
-               retval = -EBUSY;
-clean_3:
-               driver->hcd_free (hcd);
-               goto clean_2;
-       }
-       hcd->irq = dev->irq;
-
-       hcd->regs = base;
-       hcd->region = region;
-       printk (KERN_INFO "%s %s: irq %s, %s %p\n",
-               hcd->description,  dev->slot_name, bufp,
-               (driver->flags & HCD_MEMORY) ? "pci mem" : "io base",
-               base);
-
-// FIXME simpler: make "bus" be that data, not pointer to it.
-// (fixed in 2.5)
-       bus = usb_alloc_bus (&hcd_operations);
-       if (bus == NULL) {
-               dbg ("usb_alloc_bus fail");
-               retval = -ENOMEM;
-               free_irq (dev->irq, hcd);
-               goto clean_3;
-       }
-       hcd->bus = bus;
-       bus->bus_name = dev->slot_name;
-       hcd->product_desc = dev->name;
-       bus->hcpriv = (void *) hcd;
-
-       INIT_LIST_HEAD (&hcd->dev_list);
-       INIT_LIST_HEAD (&hcd->hcd_list);
-
-       down (&hcd_list_lock);
-       list_add (&hcd->hcd_list, &hcd_list);
-       up (&hcd_list_lock);
-
-       usb_register_bus (bus);
-
-       if ((retval = driver->start (hcd)) < 0)
-               usb_hcd_pci_remove (dev);
-
-       return retval;
-} 
-EXPORT_SYMBOL (usb_hcd_pci_probe);
-
-
-/* may be called without controller electrically present */
-/* may be called with controller, bus, and devices active */
-
-/**
- * usb_hcd_pci_remove - shutdown processing for PCI-based HCDs
- * @dev: USB Host Controller being removed
- * Context: !in_interrupt()
- *
- * Reverses the effect of usb_hcd_pci_probe(), first invoking
- * the HCD's stop() method.  It is always called from a thread
- * context, normally "rmmod", "apmd", or something similar.
- *
- * Store this function in the HCD's struct pci_driver as remove().
- */
-void usb_hcd_pci_remove (struct pci_dev *dev)
-{
-       struct usb_hcd          *hcd;
-       struct usb_device       *hub;
-
-       hcd = pci_get_drvdata(dev);
-       if (!hcd)
-               return;
-       printk (KERN_INFO "%s %s: remove state %x\n",
-               hcd->description,  dev->slot_name, hcd->state);
-
-       if (in_interrupt ()) BUG ();
-
-       hub = hcd->bus->root_hub;
-       hcd->state = USB_STATE_QUIESCING;
-
-       dbg ("%s: roothub graceful disconnect", hcd->bus->bus_name);
-       usb_disconnect (&hub);
-       // usb_disconnect (&hcd->bus->root_hub);
-
-       hcd->driver->stop (hcd);
-       hcd->state = USB_STATE_HALT;
-
-       free_irq (hcd->irq, hcd);
-       if (hcd->driver->flags & HCD_MEMORY) {
-               iounmap (hcd->regs);
-               release_mem_region (pci_resource_start (dev, 0),
-                       pci_resource_len (dev, 0));
-       } else {
-               release_region (pci_resource_start (dev, hcd->region),
-                       pci_resource_len (dev, hcd->region));
-       }
-
-       down (&hcd_list_lock);
-       list_del (&hcd->hcd_list);
-       up (&hcd_list_lock);
-
-       usb_deregister_bus (hcd->bus);
-       usb_free_bus (hcd->bus);
-       hcd->bus = NULL;
-
-       hcd->driver->hcd_free (hcd);
-}
-EXPORT_SYMBOL (usb_hcd_pci_remove);
-
-
-#ifdef CONFIG_PM
-
-/*
- * Some "sleep" power levels imply updating struct usb_driver
- * to include a callback asking hcds to do their bit by checking
- * if all the drivers can suspend.  Gets involved with remote wakeup.
- *
- * If there are pending urbs, then HCs will need to access memory,
- * causing extra power drain.  New sleep()/wakeup() PM calls might
- * be needed, beyond PCI suspend()/resume().  The root hub timer
- * still be accessing memory though ...
- *
- * FIXME:  USB should have some power budgeting support working with
- * all kinds of hubs.
- *
- * FIXME:  This assumes only D0->D3 suspend and D3->D0 resume.
- * D1 and D2 states should do something, yes?
- *
- * FIXME:  Should provide generic enable_wake(), calling pci_enable_wake()
- * for all supported states, so that USB remote wakeup can work for any
- * devices that support it (and are connected via powered hubs).
- *
- * FIXME:  resume doesn't seem to work right any more...
- */
-
-
-// 2.4 kernels have issued concurrent resumes (w/APM)
-// we defend against that error; PCI doesn't yet.
-
-/**
- * usb_hcd_pci_suspend - power management suspend of a PCI-based HCD
- * @dev: USB Host Controller being suspended
- *
- * Store this function in the HCD's struct pci_driver as suspend().
- */
-int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state)
-{
-       struct usb_hcd          *hcd;
-       int                     retval;
-
-       hcd = pci_get_drvdata(dev);
-       printk (KERN_INFO "%s %s: suspend to state %d\n",
-               hcd->description,  dev->slot_name, state);
-
-       pci_save_state (dev, hcd->pci_state);
-
-       // FIXME for all connected devices, leaf-to-root:
-       // driver->suspend()
-       // proposed "new 2.5 driver model" will automate that
-
-       /* driver may want to disable DMA etc */
-       retval = hcd->driver->suspend (hcd, state);
-       hcd->state = USB_STATE_SUSPENDED;
-
-       pci_set_power_state (dev, state);
-       return retval;
-}
-EXPORT_SYMBOL (usb_hcd_pci_suspend);
-
-/**
- * usb_hcd_pci_resume - power management resume of a PCI-based HCD
- * @dev: USB Host Controller being resumed
- *
- * Store this function in the HCD's struct pci_driver as resume().
- */
-int usb_hcd_pci_resume (struct pci_dev *dev)
-{
-       struct usb_hcd          *hcd;
-       int                     retval;
-
-       hcd = pci_get_drvdata(dev);
-       printk (KERN_INFO "%s %s: resume\n",
-               hcd->description,  dev->slot_name);
-
-       /* guard against multiple resumes (APM bug?) */
-       atomic_inc (&hcd->resume_count);
-       if (atomic_read (&hcd->resume_count) != 1) {
-               err ("concurrent PCI resumes for %s", hcd->bus->bus_name);
-               retval = 0;
-               goto done;
-       }
-
-       retval = -EBUSY;
-       if (hcd->state != USB_STATE_SUSPENDED) {
-               dbg ("can't resume, not suspended!");
-               goto done;
-       }
-       hcd->state = USB_STATE_RESUMING;
-
-       pci_set_power_state (dev, 0);
-       pci_restore_state (dev, hcd->pci_state);
-
-       retval = hcd->driver->resume (hcd);
-       if (!HCD_IS_RUNNING (hcd->state)) {
-               dbg ("resume %s failure, retval %d",
-                       hcd->bus->bus_name, retval);
-               hc_died (hcd);
-// FIXME:  recover, reset etc.
-       } else {
-               // FIXME for all connected devices, root-to-leaf:
-               // driver->resume ();
-               // proposed "new 2.5 driver model" will automate that
-       }
-
-done:
-       atomic_dec (&hcd->resume_count);
-       return retval;
-}
-EXPORT_SYMBOL (usb_hcd_pci_resume);
-
-#endif /* CONFIG_PM */
-
-#endif
-
-/*-------------------------------------------------------------------------*/
-
-/*
- * Generic HC operations.
- */
-
-/*-------------------------------------------------------------------------*/
-
-/* called from khubd, or root hub init threads for hcd-private init */
-static int hcd_alloc_dev (struct usb_device *udev)
-{
-       struct hcd_dev          *dev;
-       struct usb_hcd          *hcd;
-       unsigned long           flags;
-
-       if (!udev || udev->hcpriv)
-               return -EINVAL;
-       if (!udev->bus || !udev->bus->hcpriv)
-               return -ENODEV;
-       hcd = udev->bus->hcpriv;
-       if (hcd->state == USB_STATE_QUIESCING)
-               return -ENOLINK;
-
-       dev = (struct hcd_dev *) kmalloc (sizeof *dev, GFP_KERNEL);
-       if (dev == NULL)
-               return -ENOMEM;
-       memset (dev, 0, sizeof *dev);
-
-       INIT_LIST_HEAD (&dev->dev_list);
-       INIT_LIST_HEAD (&dev->urb_list);
-
-       spin_lock_irqsave (&hcd_data_lock, flags);
-       list_add (&dev->dev_list, &hcd->dev_list);
-       // refcount is implicit
-       udev->hcpriv = dev;
-       spin_unlock_irqrestore (&hcd_data_lock, flags);
-
-       return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-static void hcd_panic (void *_hcd)
-{
-       struct usb_hcd *hcd = _hcd;
-       hcd->driver->stop (hcd);
-}
-
-static void hc_died (struct usb_hcd *hcd)
-{
-       struct list_head        *devlist, *urblist;
-       struct hcd_dev          *dev;
-       struct urb              *urb;
-       unsigned long           flags;
-       
-       /* flag every pending urb as done */
-       spin_lock_irqsave (&hcd_data_lock, flags);
-       list_for_each (devlist, &hcd->dev_list) {
-               dev = list_entry (devlist, struct hcd_dev, dev_list);
-               list_for_each (urblist, &dev->urb_list) {
-                       urb = list_entry (urblist, struct urb, urb_list);
-                       dbg ("shutdown %s urb %p pipe %x, current status %d",
-                               hcd->bus->bus_name,
-                               urb, urb->pipe, urb->status);
-                       if (urb->status == -EINPROGRESS)
-                               urb->status = -ESHUTDOWN;
-               }
-       }
-       urb = (struct urb *) hcd->rh_timer.data;
-       if (urb)
-               urb->status = -ESHUTDOWN;
-       spin_unlock_irqrestore (&hcd_data_lock, flags);
-
-       if (urb)
-               rh_status_dequeue (hcd, urb);
-
-       /* hcd->stop() needs a task context */
-       INIT_TQUEUE (&hcd->work, hcd_panic, hcd);
-       (void) schedule_task (&hcd->work);
-}
-
-/*-------------------------------------------------------------------------*/
-
-static void urb_unlink (struct urb *urb)
-{
-       unsigned long           flags;
-       struct usb_device       *dev;
-
-       /* Release any periodic transfer bandwidth */
-       if (urb->bandwidth)
-               usb_release_bandwidth (urb->dev, urb,
-                       usb_pipeisoc (urb->pipe));
-
-       /* clear all state linking urb to this dev (and hcd) */
-
-       spin_lock_irqsave (&hcd_data_lock, flags);
-       list_del_init (&urb->urb_list);
-       dev = urb->dev;
-       urb->dev = NULL;
-       usb_dec_dev_use (dev);
-       spin_unlock_irqrestore (&hcd_data_lock, flags);
-}
-
-
-/* may be called in any context with a valid urb->dev usecount */
-/* caller surrenders "ownership" of urb */
-
-static int hcd_submit_urb (struct urb *urb)
-{
-       int                     status;
-       struct usb_hcd          *hcd;
-       struct hcd_dev          *dev;
-       unsigned long           flags;
-       int                     pipe, temp, max;
-       int                     mem_flags;
-
-       if (!urb || urb->hcpriv || !urb->complete)
-               return -EINVAL;
-
-       urb->status = -EINPROGRESS;
-       urb->actual_length = 0;
-       urb->bandwidth = 0;
-       INIT_LIST_HEAD (&urb->urb_list);
-
-       if (!urb->dev || !urb->dev->bus || urb->dev->devnum <= 0)
-               return -ENODEV;
-       hcd = urb->dev->bus->hcpriv;
-       dev = urb->dev->hcpriv;
-       if (!hcd || !dev)
-               return -ENODEV;
-
-       /* can't submit new urbs when quiescing, halted, ... */
-       if (hcd->state == USB_STATE_QUIESCING || !HCD_IS_RUNNING (hcd->state))
-               return -ESHUTDOWN;
-       pipe = urb->pipe;
-       temp = usb_pipetype (urb->pipe);
-       if (usb_endpoint_halted (urb->dev, usb_pipeendpoint (pipe),
-                       usb_pipeout (pipe)))
-               return -EPIPE;
-
-       /* NOTE: 2.5 passes this value explicitly in submit() */
-       mem_flags = GFP_ATOMIC;
-
-       /* FIXME there should be a sharable lock protecting us against
-        * config/altsetting changes and disconnects, kicking in here.
-        */
-
-       /* Sanity check, so HCDs can rely on clean data */
-       max = usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe));
-       if (max <= 0) {
-               err ("bogus endpoint (bad maxpacket)");
-               return -EINVAL;
-       }
-
-       /* "high bandwidth" mode, 1-3 packets/uframe? */
-       if (urb->dev->speed == USB_SPEED_HIGH) {
-               int     mult;
-               switch (temp) {
-               case PIPE_ISOCHRONOUS:
-               case PIPE_INTERRUPT:
-                       mult = 1 + ((max >> 11) & 0x03);
-                       max &= 0x03ff;
-                       max *= mult;
-               }
-       }
-
-       /* periodic transfers limit size per frame/uframe */
-       switch (temp) {
-       case PIPE_ISOCHRONOUS: {
-               int     n, len;
-
-               if (urb->number_of_packets <= 0)                    
-                       return -EINVAL;
-               for (n = 0; n < urb->number_of_packets; n++) {
-                       len = urb->iso_frame_desc [n].length;
-                       if (len < 0 || len > max) 
-                               return -EINVAL;
-               }
-
-               }
-               break;
-       case PIPE_INTERRUPT:
-               if (urb->transfer_buffer_length > max)
-                       return -EINVAL;
-       }
-
-       /* the I/O buffer must usually be mapped/unmapped */
-       if (urb->transfer_buffer_length < 0)
-               return -EINVAL;
-
-       if (urb->next) {
-               warn ("use explicit queuing not urb->next");
-               return -EINVAL;
-       }
-
-#ifdef DEBUG
-       /* stuff that drivers shouldn't do, but which shouldn't
-        * cause problems in HCDs if they get it wrong.
-        */
-       {
-       unsigned int    orig_flags = urb->transfer_flags;
-       unsigned int    allowed;
-
-       /* enforce simple/standard policy */
-       allowed = USB_ASYNC_UNLINK;     // affects later unlinks
-       allowed |= USB_NO_FSBR;         // only affects UHCI
-       switch (temp) {
-       case PIPE_CONTROL:
-               allowed |= USB_DISABLE_SPD;
-               break;
-       case PIPE_BULK:
-               allowed |= USB_DISABLE_SPD | USB_QUEUE_BULK
-                               | USB_ZERO_PACKET | URB_NO_INTERRUPT;
-               break;
-       case PIPE_INTERRUPT:
-               allowed |= USB_DISABLE_SPD;
-               break;
-       case PIPE_ISOCHRONOUS:
-               allowed |= USB_ISO_ASAP;
-               break;
-       }
-       urb->transfer_flags &= allowed;
-
-       /* fail if submitter gave bogus flags */
-       if (urb->transfer_flags != orig_flags) {
-               err ("BOGUS urb flags, %x --> %x",
-                       orig_flags, urb->transfer_flags);
-               return -EINVAL;
-       }
-       }
-#endif
-       /*
-        * Force periodic transfer intervals to be legal values that are
-        * a power of two (so HCDs don't need to).
-        *
-        * FIXME want bus->{intr,iso}_sched_horizon values here.  Each HC
-        * supports different values... this uses EHCI/UHCI defaults (and
-        * EHCI can use smaller non-default values).
-        */
-       switch (temp) {
-       case PIPE_ISOCHRONOUS:
-       case PIPE_INTERRUPT:
-               /* too small? */
-               if (urb->interval <= 0)
-                       return -EINVAL;
-               /* too big? */
-               switch (urb->dev->speed) {
-               case USB_SPEED_HIGH:    /* units are microframes */
-                       // NOTE usb handles 2^15
-                       if (urb->interval > (1024 * 8))
-                               urb->interval = 1024 * 8;
-                       temp = 1024 * 8;
-                       break;
-               case USB_SPEED_FULL:    /* units are frames/msec */
-               case USB_SPEED_LOW:
-                       if (temp == PIPE_INTERRUPT) {
-                               if (urb->interval > 255)
-                                       return -EINVAL;
-                               // NOTE ohci only handles up to 32
-                               temp = 128;
-                       } else {
-                               if (urb->interval > 1024)
-                                       urb->interval = 1024;
-                               // NOTE usb and ohci handle up to 2^15
-                               temp = 1024;
-                       }
-                       break;
-               default:
-                       return -EINVAL;
-               }
-               /* power of two? */
-               while (temp > urb->interval)
-                       temp >>= 1;
-               urb->interval = temp;
-       }
-
-
-       /*
-        * FIXME:  make urb timeouts be generic, keeping the HCD cores
-        * as simple as possible.
-        */
-
-       // NOTE:  a generic device/urb monitoring hook would go here.
-       // hcd_monitor_hook(MONITOR_URB_SUBMIT, urb)
-       // It would catch submission paths for all urbs.
-
-       /*
-        * Atomically queue the urb,  first to our records, then to the HCD.
-        * Access to urb->status is controlled by urb->lock ... changes on
-        * i/o completion (normal or fault) or unlinking.
-        */
-
-       // FIXME:  verify that quiescing hc works right (RH cleans up)
-
-       spin_lock_irqsave (&hcd_data_lock, flags);
-       if (HCD_IS_RUNNING (hcd->state) && hcd->state != USB_STATE_QUIESCING) {
-               usb_inc_dev_use (urb->dev);
-               list_add (&urb->urb_list, &dev->urb_list);
-               status = 0;
-       } else {
-               INIT_LIST_HEAD (&urb->urb_list);
-               status = -ESHUTDOWN;
-       }
-       spin_unlock_irqrestore (&hcd_data_lock, flags);
-       if (status)
-               return status;
-
-       // NOTE:  2.5 does this if !URB_NO_DMA_MAP transfer flag
-       
-       /* For 2.4, don't map bounce buffer if it's a root hub operation. */
-       if (urb->dev == hcd->bus->root_hub) {
-               status = rh_urb_enqueue (hcd, urb);
-       } else {
-#ifdef CONFIG_PCI
-               if (usb_pipecontrol (urb->pipe))
-                       urb->setup_dma = pci_map_single (
-                                       hcd->pdev,
-                                       urb->setup_packet,
-                                       sizeof (struct usb_ctrlrequest),
-                                       PCI_DMA_TODEVICE);
-               if (urb->transfer_buffer_length != 0)
-                       urb->transfer_dma = pci_map_single (
-                                       hcd->pdev,
-                                       urb->transfer_buffer,
-                                       urb->transfer_buffer_length,
-                                       usb_pipein (urb->pipe)
-                                           ? PCI_DMA_FROMDEVICE
-                                           : PCI_DMA_TODEVICE);
-#endif /* CONFIG_PCI */
-               status = hcd->driver->urb_enqueue (hcd, urb, mem_flags);
-       }
-       return status;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* called in any context */
-static int hcd_get_frame_number (struct usb_device *udev)
-{
-       struct usb_hcd  *hcd = (struct usb_hcd *)udev->bus->hcpriv;
-       return hcd->driver->get_frame_number (hcd);
-}
-
-/*-------------------------------------------------------------------------*/
-
-struct completion_splice {             // modified urb context:
-       /* did we complete? */
-       struct completion       done;
-
-       /* original urb data */
-       void                    (*complete)(struct urb *);
-       void                    *context;
-};
-
-static void unlink_complete (struct urb *urb)
-{
-       struct completion_splice        *splice;
-
-       splice = (struct completion_splice *) urb->context;
-
-       /* issue original completion call */
-       urb->complete = splice->complete;
-       urb->context = splice->context;
-       urb->complete (urb);
-
-       /* then let the synchronous unlink call complete */
-       complete (&splice->done);
-}
-
-/*
- * called in any context; note ASYNC_UNLINK restrictions
- *
- * caller guarantees urb won't be recycled till both unlink()
- * and the urb's completion function return
- */
-static int hcd_unlink_urb (struct urb *urb)
-{
-       struct hcd_dev                  *dev;
-       struct usb_hcd                  *hcd = 0;
-       unsigned long                   flags;
-       struct completion_splice        splice;
-       int                             retval;
-
-       if (!urb)
-               return -EINVAL;
-
-       /*
-        * we contend for urb->status with the hcd core,
-        * which changes it while returning the urb.
-        *
-        * Caller guaranteed that the urb pointer hasn't been freed, and
-        * that it was submitted.  But as a rule it can't know whether or
-        * not it's already been unlinked ... so we respect the reversed
-        * lock sequence needed for the usb_hcd_giveback_urb() code paths
-        * (urb lock, then hcd_data_lock) in case some other CPU is now
-        * unlinking it.
-        */
-       spin_lock_irqsave (&urb->lock, flags);
-       spin_lock (&hcd_data_lock);
-       if (!urb->hcpriv || urb->transfer_flags & USB_TIMEOUT_KILLED) {
-               retval = -EINVAL;
-               goto done;
-       }
-
-       if (!urb->dev || !urb->dev->bus) {
-               retval = -ENODEV;
-               goto done;
-       }
-
-       /* giveback clears dev; non-null means it's linked at this level */
-       dev = urb->dev->hcpriv;
-       hcd = urb->dev->bus->hcpriv;
-       if (!dev || !hcd) {
-               retval = -ENODEV;
-               goto done;
-       }
-
-       /* Any status except -EINPROGRESS means the HCD has already started
-        * to return this URB to the driver.  In that case, there's no
-        * more work for us to do.
-        *
-        * There's much magic because of "automagic resubmit" of interrupt
-        * transfers, stopped only by explicit unlinking.  We won't issue
-        * an "it's unlinked" callback more than once, but device drivers
-        * can need to retry (SMP, -EAGAIN) an unlink request as well as
-        * fake out the "not yet completed" state (set -EINPROGRESS) if
-        * unlinking from complete().  Automagic eventually vanishes.
-        *
-        * FIXME use an URB_UNLINKED flag to match URB_TIMEOUT_KILLED
-        */
-       if (urb->status != -EINPROGRESS) {
-               if (usb_pipetype (urb->pipe) == PIPE_INTERRUPT)
-                       retval = -EAGAIN;
-               else
-                       retval = -EBUSY;
-               goto done;
-       }
-
-       /* maybe set up to block on completion notification */
-       if ((urb->transfer_flags & USB_TIMEOUT_KILLED))
-               urb->status = -ETIMEDOUT;
-       else if (!(urb->transfer_flags & USB_ASYNC_UNLINK)) {
-               if (in_interrupt ()) {
-                       dbg ("non-async unlink in_interrupt");
-                       retval = -EWOULDBLOCK;
-                       goto done;
-               }
-               /* synchronous unlink: block till we see the completion */
-               init_completion (&splice.done);
-               splice.complete = urb->complete;
-               splice.context = urb->context;
-               urb->complete = unlink_complete;
-               urb->context = &splice;
-               urb->status = -ENOENT;
-       } else {
-               /* asynchronous unlink */
-               urb->status = -ECONNRESET;
-       }
-       spin_unlock (&hcd_data_lock);
-       spin_unlock_irqrestore (&urb->lock, flags);
-
-       if (urb == (struct urb *) hcd->rh_timer.data) {
-               rh_status_dequeue (hcd, urb);
-               retval = 0;
-       } else {
-               retval = hcd->driver->urb_dequeue (hcd, urb);
-// FIXME:  if retval and we tried to splice, whoa!!
-if (retval && urb->status == -ENOENT) err ("whoa! retval %d", retval);
-       }
-
-       /* block till giveback, if needed */
-       if (!(urb->transfer_flags & (USB_ASYNC_UNLINK|USB_TIMEOUT_KILLED))
-                       && HCD_IS_RUNNING (hcd->state)
-                       && !retval) {
-               wait_for_completion (&splice.done);
-       } else if ((urb->transfer_flags & USB_ASYNC_UNLINK) && retval == 0) {
-               return -EINPROGRESS;
-       }
-       goto bye;
-done:
-       spin_unlock (&hcd_data_lock);
-       spin_unlock_irqrestore (&urb->lock, flags);
-bye:
-       if (retval)
-               dbg ("%s: hcd_unlink_urb fail %d",
-                   hcd ? hcd->bus->bus_name : "(no bus?)",
-                   retval);
-       return retval;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* called by khubd, rmmod, apmd, or other thread for hcd-private cleanup */
-
-// FIXME:  likely best to have explicit per-setting (config+alt)
-// setup primitives in the usbcore-to-hcd driver API, so nothing
-// is implicit.  kernel 2.5 needs a bunch of config cleanup...
-
-static int hcd_free_dev (struct usb_device *udev)
-{
-       struct hcd_dev          *dev;
-       struct usb_hcd          *hcd;
-       unsigned long           flags;
-
-       if (!udev || !udev->hcpriv)
-               return -EINVAL;
-
-       if (!udev->bus || !udev->bus->hcpriv)
-               return -ENODEV;
-
-       // should udev->devnum == -1 ??
-
-       dev = udev->hcpriv;
-       hcd = udev->bus->hcpriv;
-
-       /* device driver problem with refcounts? */
-       if (!list_empty (&dev->urb_list)) {
-               dbg ("free busy dev, %s devnum %d (bug!)",
-                       hcd->bus->bus_name, udev->devnum);
-               return -EINVAL;
-       }
-
-       hcd->driver->free_config (hcd, udev);
-
-       spin_lock_irqsave (&hcd_data_lock, flags);
-       list_del (&dev->dev_list);
-       udev->hcpriv = NULL;
-       spin_unlock_irqrestore (&hcd_data_lock, flags);
-
-       kfree (dev);
-       return 0;
-}
-
-static struct usb_operations hcd_operations = {
-       allocate:               hcd_alloc_dev,
-       get_frame_number:       hcd_get_frame_number,
-       submit_urb:             hcd_submit_urb,
-       unlink_urb:             hcd_unlink_urb,
-       deallocate:             hcd_free_dev,
-};
-
-/*-------------------------------------------------------------------------*/
-
-static void hcd_irq (int irq, void *__hcd, struct pt_regs * r)
-{
-       struct usb_hcd          *hcd = __hcd;
-       int                     start = hcd->state;
-
-       if (unlikely (hcd->state == USB_STATE_HALT))    /* irq sharing? */
-               return;
-
-       hcd->driver->irq (hcd, r);
-       if (hcd->state != start && hcd->state == USB_STATE_HALT)
-               hc_died (hcd);
-}
-
-/*-------------------------------------------------------------------------*/
-
-/**
- * usb_hcd_giveback_urb - return URB from HCD to device driver
- * @hcd: host controller returning the URB
- * @urb: urb being returned to the USB device driver.
- * @regs: saved hardware registers (ignored on 2.4 kernels)
- * Context: in_interrupt()
- *
- * This hands the URB from HCD to its USB device driver, using its
- * completion function.  The HCD has freed all per-urb resources
- * (and is done using urb->hcpriv).  It also released all HCD locks;
- * the device driver won't cause deadlocks if it resubmits this URB,
- * and won't confuse things by modifying and resubmitting this one.
- * Bandwidth and other resources will be deallocated.
- *
- * HCDs must not use this for periodic URBs that are still scheduled
- * and will be reissued.  They should just call their completion handlers
- * until the urb is returned to the device driver by unlinking.
- *
- * NOTE that no urb->next processing is done, even for isochronous URBs.
- * ISO streaming functionality can be achieved by having completion handlers
- * re-queue URBs.  Such explicit queuing doesn't discard error reports.
- */
-void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs)
-{
-       int is_root_hub_operation;
-
-       /* Work this out here as urb_unlink clears urb->dev */
-       is_root_hub_operation = (urb->dev == hcd->bus->root_hub);
-
-       urb_unlink (urb);
-
-       // NOTE:  a generic device/urb monitoring hook would go here.
-       // hcd_monitor_hook(MONITOR_URB_FINISH, urb, dev)
-       // It would catch exit/unlink paths for all urbs, but non-exit
-       // completions for periodic urbs need hooks inside the HCD.
-       // hcd_monitor_hook(MONITOR_URB_UPDATE, urb, dev)
-
-       // NOTE:  2.5 does this if !URB_NO_DMA_MAP transfer flag
-
-#ifdef CONFIG_PCI      
-       /* For 2.4, don't unmap bounce buffer if it's a root hub operation. */
-       if (usb_pipecontrol (urb->pipe) && !is_root_hub_operation)
-               pci_unmap_single (hcd->pdev, urb->setup_dma,
-                               sizeof (struct usb_ctrlrequest),
-                               PCI_DMA_TODEVICE);
-
-       if ((urb->transfer_buffer_length != 0) && !is_root_hub_operation)
-               pci_unmap_single (hcd->pdev, urb->transfer_dma,
-                               urb->transfer_buffer_length,
-                               usb_pipein (urb->pipe)
-                                   ? PCI_DMA_FROMDEVICE
-                                   : PCI_DMA_TODEVICE);
-#endif /* CONFIG_PCI */
-
-       /* pass ownership to the completion handler */
-       urb->complete (urb);
-}
-EXPORT_SYMBOL (usb_hcd_giveback_urb);
diff --git a/linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/Makefile b/linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/Makefile
new file mode 100644 (file)
index 0000000..1b3eb41
--- /dev/null
@@ -0,0 +1,10 @@
+
+O_TARGET := drv.o
+
+subdir-$(CONFIG_XEN_USB_FRONTEND) += frontend
+obj-$(CONFIG_XEN_USB_FRONTEND) += frontend/drv.o
+
+subdir-$(CONFIG_XEN_USB_BACKEND) += backend
+obj-$(CONFIG_XEN_USB_BACKEND)    += backend/drv.o
+
+include $(TOPDIR)/Rules.make
diff --git a/linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/backend/Makefile b/linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/backend/Makefile
new file mode 100644 (file)
index 0000000..b5226dd
--- /dev/null
@@ -0,0 +1,3 @@
+O_TARGET := drv.o
+obj-y := main.o interface.o control.o # vrh.o don't think I need this!
+include $(TOPDIR)/Rules.make
diff --git a/linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/backend/common.h b/linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/backend/common.h
new file mode 100644 (file)
index 0000000..550599a
--- /dev/null
@@ -0,0 +1,87 @@
+
+#ifndef __USBIF__BACKEND__COMMON_H__
+#define __USBIF__BACKEND__COMMON_H__
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/rbtree.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <asm/io.h>
+#include <asm/setup.h>
+#include <asm/pgalloc.h>
+#include <asm-xen/ctrl_if.h>
+#include <asm-xen/hypervisor.h>
+
+#include "../usbif.h"
+
+#if 0
+#define ASSERT(_p) \
+    if ( !(_p) ) { printk("Assertion '%s' failed, line %d, file %s", #_p , \
+    __LINE__, __FILE__); *(int*)0=0; }
+#define DPRINTK(_f, _a...) printk(KERN_ALERT "(file=%s, line=%d) " _f, \
+                           __FILE__ , __LINE__ , ## _a )
+#else
+#define ASSERT(_p) ((void)0)
+#define DPRINTK(_f, _a...) ((void)0)
+#endif
+
+typedef struct usbif_priv_st usbif_priv_t;
+
+struct usbif_priv_st {
+    /* Unique identifier for this interface. */
+    domid_t          domid;
+    unsigned int     handle;
+    /* Physical parameters of the comms window. */
+    unsigned long    shmem_frame;
+    unsigned int     evtchn;
+    int              irq;
+    /* Comms information. */
+    usbif_t      *usb_ring_base; /* ioremap()'ed ptr to shmem_frame. */
+    USBIF_RING_IDX     usb_req_cons;  /* Request consumer. */
+    USBIF_RING_IDX     usb_resp_prod; /* Private version of resp. producer. */
+    /* Private fields. */
+    enum { DISCONNECTED, DISCONNECTING, CONNECTED } status;
+    /*
+     * DISCONNECT response is deferred until pending requests are ack'ed.
+     * We therefore need to store the id from the original request.
+     */
+    u8                   disconnect_rspid;
+    usbif_priv_t *hash_next;
+    struct list_head     usbif_list;
+    spinlock_t           usb_ring_lock;
+    atomic_t             refcnt;
+    atomic_t             work_scheduled;
+
+    struct work_struct work;
+};
+
+void usbif_create(usbif_be_create_t *create);
+void usbif_destroy(usbif_be_destroy_t *destroy);
+void usbif_connect(usbif_be_connect_t *connect);
+int  usbif_disconnect(usbif_be_disconnect_t *disconnect, u8 rsp_id);
+void usbif_disconnect_complete(usbif_priv_t *up);
+
+void usbif_release_port(usbif_be_release_port_t *msg);
+int usbif_claim_port(usbif_be_claim_port_t *msg);
+void usbif_release_ports(usbif_priv_t *up);
+
+usbif_priv_t *usbif_find(domid_t domid);
+#define usbif_get(_b) (atomic_inc(&(_b)->refcnt))
+#define usbif_put(_b)                             \
+    do {                                          \
+        if ( atomic_dec_and_test(&(_b)->refcnt) ) \
+            usbif_disconnect_complete(_b);        \
+    } while (0)
+
+
+void usbif_interface_init(void);
+void usbif_ctrlif_init(void);
+
+void usbif_deschedule(usbif_priv_t *usbif);
+
+irqreturn_t usbif_be_int(int irq, void *dev_id, struct pt_regs *regs);
+
+#endif /* __USBIF__BACKEND__COMMON_H__ */
diff --git a/linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/backend/control.c b/linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/backend/control.c
new file mode 100644 (file)
index 0000000..899394a
--- /dev/null
@@ -0,0 +1,77 @@
+/******************************************************************************
+ * arch/xen/drivers/usbif/backend/control.c
+ * 
+ * Routines for interfacing with the control plane.
+ * 
+ * Copyright (c) 2004, Keir Fraser
+ */
+
+#include "common.h"
+
+static void usbif_ctrlif_rx(ctrl_msg_t *msg, unsigned long id)
+{
+    DPRINTK("Received usbif backend message, subtype=%d\n", msg->subtype);
+    
+    switch ( msg->subtype )
+    {
+    case CMSG_USBIF_BE_CREATE:
+        if ( msg->length != sizeof(usbif_be_create_t) )
+            goto parse_error;
+        usbif_create((usbif_be_create_t *)&msg->msg[0]);
+        break;        
+    case CMSG_USBIF_BE_DESTROY:
+        if ( msg->length != sizeof(usbif_be_destroy_t) )
+            goto parse_error;
+        usbif_destroy((usbif_be_destroy_t *)&msg->msg[0]);
+        break;        
+    case CMSG_USBIF_BE_CONNECT:
+        if ( msg->length != sizeof(usbif_be_connect_t) )
+            goto parse_error;
+        usbif_connect((usbif_be_connect_t *)&msg->msg[0]);
+        break;        
+    case CMSG_USBIF_BE_DISCONNECT:
+        if ( msg->length != sizeof(usbif_be_disconnect_t) )
+            goto parse_error;
+        if ( !usbif_disconnect((usbif_be_disconnect_t *)&msg->msg[0],msg->id) )
+            return; /* Sending the response is deferred until later. */
+        break;        
+    case CMSG_USBIF_BE_CLAIM_PORT:
+        if ( msg->length != sizeof(usbif_be_claim_port_t) )
+            goto parse_error;
+       usbif_claim_port((usbif_be_claim_port_t *)&msg->msg[0]);
+        break;
+    case CMSG_USBIF_BE_RELEASE_PORT:
+        if ( msg->length != sizeof(usbif_be_release_port_t) )
+            goto parse_error;
+        usbif_release_port((usbif_be_release_port_t *)&msg->msg[0]);
+        break;
+    default:
+        goto parse_error;
+    }
+
+    ctrl_if_send_response(msg);
+    return;
+
+ parse_error:
+    DPRINTK("Parse error while reading message subtype %d, len %d\n",
+            msg->subtype, msg->length);
+    msg->length = 0;
+    ctrl_if_send_response(msg);
+}
+
+void usbif_ctrlif_init(void)
+{
+    ctrl_msg_t                       cmsg;
+    usbif_be_driver_status_changed_t st;
+
+    (void)ctrl_if_register_receiver(CMSG_USBIF_BE, usbif_ctrlif_rx, 
+                                    CALLBACK_IN_BLOCKING_CONTEXT);
+
+    /* Send a driver-UP notification to the domain controller. */
+    cmsg.type      = CMSG_USBIF_BE;
+    cmsg.subtype   = CMSG_USBIF_BE_DRIVER_STATUS_CHANGED;
+    cmsg.length    = sizeof(usbif_be_driver_status_changed_t);
+    st.status      = USBIF_DRIVER_STATUS_UP;
+    memcpy(cmsg.msg, &st, sizeof(st));
+    ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
+}
diff --git a/linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/backend/interface.c b/linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/backend/interface.c
new file mode 100644 (file)
index 0000000..7b49ae5
--- /dev/null
@@ -0,0 +1,248 @@
+/******************************************************************************
+ * arch/xen/drivers/usbif/backend/interface.c
+ * 
+ * USB device interface management.
+ * 
+ * by Mark Williamson, Copyright (c) 2004
+ */
+
+
+/******************************************************************************
+ * arch/xen/drivers/blkif/backend/interface.c
+ * 
+ * Block-device interface management.
+ * 
+ * Copyright (c) 2004, Keir Fraser
+ */
+
+#include "common.h"
+
+#define USBIF_HASHSZ 1024
+#define USBIF_HASH(_d) (((int)(_d))&(USBIF_HASHSZ-1))
+
+static kmem_cache_t      *usbif_priv_cachep;
+static usbif_priv_t      *usbif_priv_hash[USBIF_HASHSZ];
+
+usbif_priv_t *usbif_find(domid_t domid)
+{
+    usbif_priv_t *up = usbif_priv_hash[USBIF_HASH(domid)];
+    while ( (up != NULL ) && ( up->domid != domid ) )
+        up = up->hash_next;
+    return up;
+}
+
+static void __usbif_disconnect_complete(void *arg)
+{
+    usbif_priv_t         *usbif = (usbif_priv_t *)arg;
+    ctrl_msg_t            cmsg;
+    usbif_be_disconnect_t disc;
+
+    /*
+     * These can't be done in usbif_disconnect() because at that point there
+     * may be outstanding requests at the device whose asynchronous responses
+     * must still be notified to the remote driver.
+     */
+    unbind_evtchn_from_irq(usbif->evtchn);
+    vfree(usbif->usb_ring_base);
+
+    /* Construct the deferred response message. */
+    cmsg.type         = CMSG_USBIF_BE;
+    cmsg.subtype      = CMSG_USBIF_BE_DISCONNECT;
+    cmsg.id           = usbif->disconnect_rspid;
+    cmsg.length       = sizeof(usbif_be_disconnect_t);
+    disc.domid        = usbif->domid;
+    disc.status       = USBIF_BE_STATUS_OKAY;
+    memcpy(cmsg.msg, &disc, sizeof(disc));
+
+    /*
+     * Make sure message is constructed /before/ status change, because
+     * after the status change the 'usbif' structure could be deallocated at
+     * any time. Also make sure we send the response /after/ status change,
+     * as otherwise a subsequent CONNECT request could spuriously fail if
+     * another CPU doesn't see the status change yet.
+     */
+    mb();
+    if ( usbif->status != DISCONNECTING )
+        BUG();
+    usbif->status = DISCONNECTED;
+    mb();
+
+    /* Send the successful response. */
+    ctrl_if_send_response(&cmsg);
+}
+
+void usbif_disconnect_complete(usbif_priv_t *up)
+{
+    INIT_WORK(&up->work, __usbif_disconnect_complete, (void *)up);
+    schedule_work(&up->work);
+}
+
+void usbif_create(usbif_be_create_t *create)
+{
+    domid_t       domid  = create->domid;
+    usbif_priv_t **pup, *up;
+
+    if ( (up = kmem_cache_alloc(usbif_priv_cachep, GFP_KERNEL)) == NULL )
+    {
+        DPRINTK("Could not create usbif: out of memory\n");
+        create->status = USBIF_BE_STATUS_OUT_OF_MEMORY;
+        return;
+    }
+
+    memset(up, 0, sizeof(*up));
+    up->domid  = domid;
+    up->status = DISCONNECTED;
+    spin_lock_init(&up->usb_ring_lock);
+    atomic_set(&up->refcnt, 0);
+
+    pup = &usbif_priv_hash[USBIF_HASH(domid)];
+    while ( *pup != NULL )
+    {
+        if ( (*pup)->domid == domid )
+        {
+            create->status = USBIF_BE_STATUS_INTERFACE_EXISTS;
+            kmem_cache_free(usbif_priv_cachep, up);
+            return;
+        }
+        pup = &(*pup)->hash_next;
+    }
+
+    up->hash_next = *pup;
+    *pup = up;
+
+    create->status = USBIF_BE_STATUS_OKAY;
+}
+
+void usbif_destroy(usbif_be_destroy_t *destroy)
+{
+    domid_t       domid  = destroy->domid;
+    usbif_priv_t  **pup, *up;
+
+    pup = &usbif_priv_hash[USBIF_HASH(domid)];
+    while ( (up = *pup) != NULL )
+    {
+        if ( up->domid == domid )
+        {
+            if ( up->status != DISCONNECTED )
+                goto still_connected;
+            goto destroy;
+        }
+        pup = &up->hash_next;
+    }
+
+    destroy->status = USBIF_BE_STATUS_INTERFACE_NOT_FOUND;
+    return;
+
+ still_connected:
+    destroy->status = USBIF_BE_STATUS_INTERFACE_CONNECTED;
+    return;
+
+ destroy:
+    *pup = up->hash_next;
+    usbif_release_ports(up);
+    kmem_cache_free(usbif_priv_cachep, up);
+    destroy->status = USBIF_BE_STATUS_OKAY;
+}
+
+void usbif_connect(usbif_be_connect_t *connect)
+{
+    domid_t       domid  = connect->domid;
+    unsigned int  evtchn = connect->evtchn;
+    unsigned long shmem_frame = connect->shmem_frame;
+    struct vm_struct *vma;
+    pgprot_t      prot;
+    int           error;
+    usbif_priv_t *up;
+
+    up = usbif_find(domid);
+    if ( unlikely(up == NULL) )
+    {
+        DPRINTK("usbif_connect attempted for non-existent usbif (%u)\n", 
+                connect->domid); 
+        connect->status = USBIF_BE_STATUS_INTERFACE_NOT_FOUND;
+        return;
+    }
+
+    if ( (vma = get_vm_area(PAGE_SIZE, VM_IOREMAP)) == NULL )
+    {
+        connect->status = USBIF_BE_STATUS_OUT_OF_MEMORY;
+        return;
+    }
+
+    prot = __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED);
+    error = direct_remap_area_pages(&init_mm, VMALLOC_VMADDR(vma->addr),
+                                    shmem_frame<<PAGE_SHIFT, PAGE_SIZE,
+                                    prot, domid);
+    if ( error != 0 )
+    {
+        if ( error == -ENOMEM )
+            connect->status = USBIF_BE_STATUS_OUT_OF_MEMORY;
+        else if ( error == -EFAULT )
+            connect->status = USBIF_BE_STATUS_MAPPING_ERROR;
+        else
+            connect->status = USBIF_BE_STATUS_ERROR;
+        vfree(vma->addr);
+        return;
+    }
+
+    if ( up->status != DISCONNECTED )
+    {
+        connect->status = USBIF_BE_STATUS_INTERFACE_CONNECTED;
+        vfree(vma->addr);
+        return;
+    }
+
+    up->evtchn        = evtchn;
+    up->irq           = bind_evtchn_to_irq(evtchn);
+    up->shmem_frame   = shmem_frame;
+    up->usb_ring_base = (usbif_t *)vma->addr;
+    up->status        = CONNECTED;
+    usbif_get(up);
+
+    request_irq(up->irq, usbif_be_int, 0, "usbif-backend", up);
+
+    connect->status = USBIF_BE_STATUS_OKAY;
+}
+
+/* Remove URBs for this interface before destroying it. */
+void usbif_deschedule(usbif_priv_t *up)
+{
+    remove_from_usbif_list(up);
+}
+
+int usbif_disconnect(usbif_be_disconnect_t *disconnect, u8 rsp_id)
+{
+    domid_t       domid  = disconnect->domid;
+    usbif_priv_t *up;
+
+    up = usbif_find(domid);
+    if ( unlikely(up == NULL) )
+    {
+        DPRINTK("usbif_disconnect attempted for non-existent usbif"
+                " (%u)\n", disconnect->domid); 
+        disconnect->status = USBIF_BE_STATUS_INTERFACE_NOT_FOUND;
+        return 1; /* Caller will send response error message. */
+    }
+
+    if ( up->status == CONNECTED )
+    {
+        up->status = DISCONNECTING;
+        up->disconnect_rspid = rsp_id;
+        wmb(); /* Let other CPUs see the status change. */
+        free_irq(up->irq, up);
+       usbif_deschedule(up);
+        usbif_put(up);
+        return 0; /* Caller should not send response message. */
+    }
+
+    disconnect->status = USBIF_BE_STATUS_OKAY;
+    return 1;
+}
+
+void __init usbif_interface_init(void)
+{
+    usbif_priv_cachep = kmem_cache_create("usbif_priv_cache",
+                                         sizeof(usbif_priv_t), 
+                                         0, 0, NULL, NULL);
+    memset(usbif_priv_hash, 0, sizeof(usbif_priv_hash));
+}
diff --git a/linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/backend/main.c b/linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/backend/main.c
new file mode 100644 (file)
index 0000000..51ce5bd
--- /dev/null
@@ -0,0 +1,1011 @@
+/******************************************************************************
+ * arch/xen/drivers/usbif/backend/main.c
+ * 
+ * Backend for the Xen virtual USB driver - provides an abstraction of a
+ * USB host controller to the corresponding frontend driver.
+ *
+ * by Mark Williamson, Copyright (c) 2004 Intel Research Cambridge
+ *
+ * Based on arch/xen/drivers/blkif/backend/main.c
+ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
+ */
+
+#include "common.h"
+
+
+#include <linux/list.h>
+#include <linux/usb.h>
+#include <linux/spinlock.h>
+#include <linux/module.h>
+#include <linux/tqueue.h>
+
+/*
+ * This is rather arbitrary.
+ */
+#define MAX_PENDING_REQS 4
+#define BATCH_PER_DOMAIN 1
+
+static unsigned long mmap_vstart;
+
+/* Needs to be sufficiently large that we can map the (large) buffers
+ * the USB mass storage driver wants. */
+#define MMAP_PAGES_PER_REQUEST \
+    (128)
+#define MMAP_PAGES             \
+    (MAX_PENDING_REQS * MMAP_PAGES_PER_REQUEST)
+
+#define MMAP_VADDR(_req,_seg)                        \
+    (mmap_vstart +                                   \
+     ((_req) * MMAP_PAGES_PER_REQUEST * PAGE_SIZE) + \
+     ((_seg) * PAGE_SIZE))
+
+#define MIN(x,y) ( ( x < y ) ? x : y )
+
+static spinlock_t owned_ports_lock;
+LIST_HEAD(owned_ports);
+
+/* A list of these structures is used to track ownership of physical USB
+ * ports. */
+typedef struct 
+{
+    usbif_priv_t     *usbif_priv;
+    char             path[16];
+    int               guest_port;
+    int enabled;
+    struct list_head  list;
+    unsigned long guest_address; /* The USB device address that has been
+                                  * assigned by the guest. */
+    int               dev_present; /* Is there a device present? */
+    struct usb_device * dev;
+    unsigned long ifaces;  /* What interfaces are present on this device? */
+} owned_port_t;
+
+
+/*
+ * Each outstanding request that we've passed to the lower device layers has a
+ * 'pending_req' allocated to it.  The request is complete, the specified
+ * domain has a response queued for it, with the saved 'id' passed back.
+ */
+typedef struct {
+    usbif_priv_t       *usbif_priv;
+    usbif_iso_t        *iso_sched;
+    unsigned long      id;
+    int                nr_pages;
+    unsigned short     operation;
+    int                status;
+} pending_req_t;
+
+/*
+ * We can't allocate pending_req's in order, since they may complete out of 
+ * order. We therefore maintain an allocation ring. This ring also indicates 
+ * when enough work has been passed down -- at that point the allocation ring 
+ * will be empty.
+ */
+static pending_req_t pending_reqs[MAX_PENDING_REQS];
+static unsigned char pending_ring[MAX_PENDING_REQS];
+static spinlock_t pend_prod_lock = SPIN_LOCK_UNLOCKED;
+
+/* NB. We use a different index type to differentiate from shared blk rings. */
+typedef unsigned int PEND_RING_IDX;
+#define MASK_PEND_IDX(_i) ((_i)&(MAX_PENDING_REQS-1))
+static PEND_RING_IDX pending_prod, pending_cons;
+#define NR_PENDING_REQS (MAX_PENDING_REQS - pending_prod + pending_cons)
+
+static int do_usb_io_op(usbif_priv_t *usbif, int max_to_do);
+static void make_response(usbif_priv_t *usbif, unsigned long id, 
+                          unsigned short op, int st, int inband,
+                         unsigned long actual_length);
+static void dispatch_usb_probe(usbif_priv_t *up, unsigned long id, unsigned long port);
+static void dispatch_usb_io(usbif_priv_t *up, usbif_request_t *req);    
+static void dispatch_usb_reset(usbif_priv_t *up, unsigned long portid);
+static owned_port_t *usbif_find_port(char *);
+
+
+void dump_port(owned_port_t *p)
+{
+    printk("owned_port_t @ %p\n", p);
+    printk("  usbif_priv @ %p\n", p->usbif_priv);
+    printk("  path: %s\n", p->path);
+    printk("  guest_port: %d\n", p->guest_port);
+    printk("  guest_address: %ld\n", p->guest_address);
+    printk("  dev_present: %d\n", p->dev_present);
+    printk("  dev @ %p\n", p->dev);
+    printk("  ifaces: 0x%lx\n", p->ifaces);
+}
+
+
+
+static void fast_flush_area(int idx, int nr_pages)
+{
+    multicall_entry_t mcl[MMAP_PAGES_PER_REQUEST];
+    int               i;
+
+    for ( i = 0; i < nr_pages; i++ )
+    {
+        mcl[i].op = __HYPERVISOR_update_va_mapping;
+        mcl[i].args[0] = MMAP_VADDR(idx, i) >> PAGE_SHIFT;
+        mcl[i].args[1] = 0;
+        mcl[i].args[2] = 0;
+    }
+
+    mcl[nr_pages-1].args[2] = UVMF_FLUSH_TLB;
+    if ( unlikely(HYPERVISOR_multicall(mcl, nr_pages) != 0) )
+        BUG();
+}
+
+
+/******************************************************************
+ * USB INTERFACE SCHEDULER LIST MAINTENANCE
+ */
+
+static struct list_head usbio_schedule_list;
+static spinlock_t usbio_schedule_list_lock;
+
+static int __on_usbif_list(usbif_priv_t *up)
+{
+    return up->usbif_list.next != NULL;
+}
+
+void remove_from_usbif_list(usbif_priv_t *up)
+{
+    unsigned long flags;
+    if ( !__on_usbif_list(up) ) return;
+    spin_lock_irqsave(&usbio_schedule_list_lock, flags);
+    if ( __on_usbif_list(up) )
+    {
+        list_del(&up->usbif_list);
+        up->usbif_list.next = NULL;
+        usbif_put(up);
+    }
+    spin_unlock_irqrestore(&usbio_schedule_list_lock, flags);
+}
+
+static void add_to_usbif_list_tail(usbif_priv_t *up)
+{
+    unsigned long flags;
+    if ( __on_usbif_list(up) ) return;
+    spin_lock_irqsave(&usbio_schedule_list_lock, flags);
+    if ( !__on_usbif_list(up) && (up->status == CONNECTED) )
+    {
+        list_add_tail(&up->usbif_list, &usbio_schedule_list);
+        usbif_get(up);
+    }
+    spin_unlock_irqrestore(&usbio_schedule_list_lock, flags);
+}
+
+
+/******************************************************************
+ * COMPLETION CALLBACK -- Called as urb->complete()
+ */
+
+static void maybe_trigger_usbio_schedule(void);
+
+static void __end_usb_io_op(struct urb *purb)
+{
+    unsigned long flags;
+    pending_req_t *pending_req;
+    int pending_idx;
+
+    pending_req = purb->context;
+
+/*     printk("Completed for id = %p to 0x%lx - 0x%lx\n", pending_req->id, */
+/*            virt_to_machine(purb->transfer_buffer), */
+/*            virt_to_machine(purb->transfer_buffer) */
+/*            + pending_req->nr_pages * PAGE_SIZE); */
+
+    pending_idx = pending_req - pending_reqs;
+
+    ASSERT(purb->actual_length <= purb->transfer_buffer_length);
+    ASSERT(purb->actual_length <= pending_req->nr_pages * PAGE_SIZE);
+    
+    /* An error fails the entire request. */
+    if ( purb->status )
+    {
+        printk("URB @ %p failed. Status %d\n", purb, purb->status);
+    }
+
+    if ( usb_pipetype(purb->pipe) == 0 )
+    {
+        int i;
+        usbif_iso_t *sched = (usbif_iso_t *)MMAP_VADDR(pending_idx, pending_req->nr_pages - 1);
+
+        ASSERT(sched == pending_req->sched);
+
+       //      printk("writing back schedule at %p\n", sched);
+
+        /* If we're dealing with an iso pipe, we need to copy back the schedule. */
+        for ( i = 0; i < purb->number_of_packets; i++ )
+        {
+            sched[i].length = purb->iso_frame_desc[i].actual_length;
+            ASSERT(sched[i].buffer_offset ==
+                   purb->iso_frame_desc[i].offset);
+            sched[i].status = purb->iso_frame_desc[i].status;
+        }
+    }
+    
+    //    printk("Flushing %d pages\n", pending_req->nr_pages);
+    fast_flush_area(pending_req - pending_reqs, pending_req->nr_pages);
+
+    kfree(purb->setup_packet);
+
+    spin_lock_irqsave(&pending_req->usbif_priv->usb_ring_lock, flags);
+    make_response(pending_req->usbif_priv, pending_req->id,
+                 pending_req->operation, pending_req->status, 0, purb->actual_length);
+    spin_unlock_irqrestore(&pending_req->usbif_priv->usb_ring_lock, flags);
+    usbif_put(pending_req->usbif_priv);
+
+    usb_free_urb(purb);
+
+    /* Free the pending request. */
+    spin_lock_irqsave(&pend_prod_lock, flags);
+    pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx;
+    spin_unlock_irqrestore(&pend_prod_lock, flags);
+
+    rmb();
+
+    /* Check for anything still waiting in the rings, having freed a request... */
+    maybe_trigger_usbio_schedule();
+}
+
+/******************************************************************
+ * SCHEDULER FUNCTIONS
+ */
+
+static DECLARE_WAIT_QUEUE_HEAD(usbio_schedule_wait);
+
+static int usbio_schedule(void *arg)
+{
+    DECLARE_WAITQUEUE(wq, current);
+
+    usbif_priv_t          *up;
+    struct list_head *ent;
+
+    daemonize();
+
+    for ( ; ; )
+    {
+        /* Wait for work to do. */
+        add_wait_queue(&usbio_schedule_wait, &wq);
+        set_current_state(TASK_INTERRUPTIBLE);
+        if ( (NR_PENDING_REQS == MAX_PENDING_REQS) || 
+             list_empty(&usbio_schedule_list) )
+            schedule();
+        __set_current_state(TASK_RUNNING);
+        remove_wait_queue(&usbio_schedule_wait, &wq);
+
+        /* Queue up a batch of requests. */
+        while ( (NR_PENDING_REQS < MAX_PENDING_REQS) &&
+                !list_empty(&usbio_schedule_list) )
+        {
+            ent = usbio_schedule_list.next;
+            up = list_entry(ent, usbif_priv_t, usbif_list);
+            usbif_get(up);
+            remove_from_usbif_list(up);
+            if ( do_usb_io_op(up, BATCH_PER_DOMAIN) )
+                add_to_usbif_list_tail(up);
+            usbif_put(up);
+        }
+    }
+}
+
+static void maybe_trigger_usbio_schedule(void)
+{
+    /*
+     * Needed so that two processes, who together make the following predicate
+     * true, don't both read stale values and evaluate the predicate
+     * incorrectly. Incredibly unlikely to stall the scheduler on x86, but...
+     */
+    smp_mb();
+
+    if ( !list_empty(&usbio_schedule_list) )
+        wake_up(&usbio_schedule_wait);
+}
+
+
+/******************************************************************************
+ * NOTIFICATION FROM GUEST OS.
+ */
+
+irqreturn_t usbif_be_int(int irq, void *dev_id, struct pt_regs *regs)
+{
+    usbif_priv_t *up = dev_id;
+
+    smp_mb();
+
+    add_to_usbif_list_tail(up); 
+
+    /* Will in fact /always/ trigger an io schedule in this case. */
+    maybe_trigger_usbio_schedule();
+
+    return IRQ_HANDLED;
+}
+
+
+
+/******************************************************************
+ * DOWNWARD CALLS -- These interface with the usb-device layer proper.
+ */
+
+static int do_usb_io_op(usbif_priv_t *up, int max_to_do)
+{
+    usbif_t *usb_ring = up->usb_ring_base;
+    usbif_request_t *req;
+    USBIF_RING_IDX i, rp;
+    int more_to_do = 0;
+    unsigned long flags;
+
+    spin_lock_irqsave(&up->usb_ring_lock, flags);
+
+    rp = usb_ring->req_prod;
+    rmb(); /* Ensure we see queued requests up to 'rp'. */
+    
+    /* Take items off the comms ring, taking care not to overflow. */
+    for ( i = up->usb_req_cons; 
+          (i != rp) && ((i-up->usb_resp_prod) != USBIF_RING_SIZE);
+          i++ )
+    {
+        if ( (max_to_do-- == 0) || (NR_PENDING_REQS == MAX_PENDING_REQS) )
+        {
+            more_to_do = 1;
+            break;
+        }
+
+        req = &usb_ring->ring[MASK_USBIF_IDX(i)].req;
+        
+        switch ( req->operation )
+        {
+        case USBIF_OP_PROBE:
+            dispatch_usb_probe(up, req->id, req->port);
+            break;
+
+        case USBIF_OP_IO:
+         /* Assemble an appropriate URB. */
+         dispatch_usb_io(up, req);
+          break;
+
+       case USBIF_OP_RESET:
+         dispatch_usb_reset(up, req->port);
+          break;
+
+        default:
+            DPRINTK("error: unknown USB io operation [%d]\n",
+                    req->operation);
+            make_response(up, req->id, req->operation, -EINVAL, 0, 0);
+            break;
+        }
+    }
+
+    up->usb_req_cons = i;
+
+    spin_unlock_irqrestore(&up->usb_ring_lock, flags);
+
+    return more_to_do;
+}
+
+static owned_port_t *find_guest_port(usbif_priv_t *up, int port)
+{
+    unsigned long flags;
+    struct list_head *l;
+
+    spin_lock_irqsave(&owned_ports_lock, flags);
+    list_for_each(l, &owned_ports)
+    {
+        owned_port_t *p = list_entry(l, owned_port_t, list);
+        if(p->usbif_priv == up && p->guest_port == port)
+        {
+            spin_unlock_irqrestore(&owned_ports_lock, flags);
+            return p;
+        }
+    }
+    spin_unlock_irqrestore(&owned_ports_lock, flags);
+
+    return NULL;
+}
+
+static void dispatch_usb_reset(usbif_priv_t *up, unsigned long portid)
+{
+    owned_port_t *port = find_guest_port(up, portid);
+    int ret = 0;
+
+
+    /* Allowing the guest to actually reset the device causes more problems
+     * than it's worth.  We just fake it out in software but we will do a real
+     * reset when the interface is destroyed. */
+
+#if 0
+    printk("Reset port %d\n", portid);
+
+    dump_port(port);
+#endif
+
+    port->guest_address = 0;
+    /* If there's an attached device then the port is now enabled. */
+    if ( port->dev_present )
+        port->enabled = 1;
+    else
+        port->enabled = 0;
+
+    make_response(up, 0, USBIF_OP_RESET, ret, 0, 0);
+}
+
+static void dispatch_usb_probe(usbif_priv_t *up, unsigned long id, unsigned long portid)
+{
+    owned_port_t *port = find_guest_port(up, portid);
+    int ret;
+    if ( port != NULL )
+        ret = port->dev_present;
+    else
+    {
+        ret = -EINVAL;
+        printk("dispatch_usb_probe(): invalid port probe request (port %ld)\n",
+              portid);
+    }
+
+    /* Probe result is sent back in-band.  Probes don't have an associated id
+     * right now... */
+    make_response(up, id, USBIF_OP_PROBE, ret, portid, 0);
+}
+
+owned_port_t *find_port_for_request(usbif_priv_t *up, usbif_request_t *req);
+
+static void dump_request(usbif_request_t *req)
+{    
+    printk("id = 0x%lx\n", req->id);
+    
+       printk("devnum %d\n", req->devnum);
+       printk("endpoint 0x%x\n", req->endpoint);
+       printk("direction %d\n", req->direction);
+       printk("speed %d\n", req->speed);
+        printk("pipe_type 0x%x\n", req->pipe_type);
+        printk("transfer_buffer 0x%lx\n", req->transfer_buffer);
+        printk("length 0x%lx\n", req->length);
+        printk("transfer_flags 0x%lx\n", req->transfer_flags);
+        printk("setup = { 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n",
+               req->setup[0], req->setup[1], req->setup[2], req->setup[3],
+               req->setup[4], req->setup[5], req->setup[6], req->setup[7]);
+        printk("iso_schedule = 0x%lx\n", req->iso_schedule);
+        printk("num_iso %ld\n", req->num_iso);
+}
+
+void dump_urb(struct urb *urb)
+{
+    printk("dumping urb @ %p\n", urb);
+
+#define DUMP_URB_FIELD(name, format) printk("  " # name " " format "\n", urb-> name)
+    
+    DUMP_URB_FIELD(pipe, "0x%x");
+    DUMP_URB_FIELD(status, "%d");
+    DUMP_URB_FIELD(transfer_flags, "0x%x");    
+    DUMP_URB_FIELD(transfer_buffer, "%p");
+    DUMP_URB_FIELD(transfer_buffer_length, "%d");
+    DUMP_URB_FIELD(actual_length, "%d");
+}
+
+
+static void dispatch_usb_io(usbif_priv_t *up, usbif_request_t *req)
+{
+    unsigned long buffer_mach;
+    int i = 0, offset = 0,
+        pending_idx = pending_ring[MASK_PEND_IDX(pending_cons)];
+    pending_req_t *pending_req;
+    unsigned long  remap_prot;
+    multicall_entry_t mcl[MMAP_PAGES_PER_REQUEST];
+    struct urb *purb = NULL;
+    owned_port_t *port;
+    unsigned char *setup;    
+
+//    dump_request(req);
+
+    if ( NR_PENDING_REQS == MAX_PENDING_REQS )
+    {
+        printk("usbback: Max requests already queued.  Now giving up!\n");
+        
+        return;
+    }
+
+    port = find_port_for_request(up, req);
+
+    if(port == NULL)
+    {
+       printk("No such device! (%d)\n", req->devnum);
+       dump_request(req);
+
+        make_response(up, req->id, req->operation, -ENODEV, 0, 0);
+       return;
+    }
+
+    setup = kmalloc(8, GFP_ATOMIC | GFP_NOIO);
+
+    if ( setup == NULL )
+        goto no_mem;
+   
+    /* Copy request out for safety. */
+    memcpy(setup, req->setup, 8);
+
+    if( setup[0] == 0x0 && setup[1] == 0x5)
+    {
+        /* To virtualise the USB address space, we need to intercept
+         * set_address messages and emulate.  From the USB specification:
+         * bmRequestType = 0x0;
+         * Brequest = SET_ADDRESS (i.e. 0x5)
+         * wValue = device address
+         * wIndex = 0
+         * wLength = 0
+         * data = None
+         */
+        /* Store into the guest transfer buffer using cpu_to_le16 */
+        port->guest_address = le16_to_cpu(*(u16 *)(setup + 2));
+        /* Make a successful response.  That was easy! */
+
+        make_response(up, req->id, req->operation, 0, 0, 0);
+
+       kfree(setup);
+        return;
+    }
+    else if ( setup[0] == 0x0 && setup[1] == 0x9 )
+    {
+        /* The host kernel needs to know what device configuration is in use
+         * because various error checks get confused otherwise.  We just do
+         * configuration settings here, under controlled conditions.
+         */
+        usb_set_configuration(port->dev, setup[2]);
+
+        make_response(up, req->id, req->operation, 0, 0, 0);
+
+        kfree(setup);
+        return;
+    }
+
+    else if ( setup[0] == 0x1 && setup[1] == 0xB )
+    {
+        /* The host kernel needs to know what device interface is in use
+         * because various error checks get confused otherwise.  We just do
+         * configuration settings here, under controlled conditions.
+         */
+        usb_set_interface(port->dev, (setup[4] | setup[5] << 8),
+                          (setup[2] | setup[3] << 8) );
+
+        make_response(up, req->id, req->operation, 0, 0, 0);
+
+        kfree(setup);
+        return;
+    }
+
+    if ( ( req->transfer_buffer - (req->transfer_buffer & PAGE_MASK)
+          + req->length )
+        > MMAP_PAGES_PER_REQUEST * PAGE_SIZE )
+    {
+        printk("usbback: request of %d bytes too large, failing it\n", req->length);
+        make_response(up, req->id, req->operation, -EINVAL, 0, 0);
+        kfree(setup);
+        return;
+    }
+    
+    buffer_mach = req->transfer_buffer;
+
+    if( buffer_mach == 0 )
+       goto no_remap;
+
+    ASSERT((req->length >> PAGE_SHIFT) <= MMAP_PAGES_PER_REQUEST);
+    ASSERT(buffer_mach);
+
+    /* Always map writeable for now. */
+    remap_prot = _PAGE_PRESENT|_PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_RW;
+
+    for ( i = 0, offset = 0; offset < req->length;
+          i++, offset += PAGE_SIZE )
+    {
+      //        printk("length = %d, offset = %d, looping!\n", req->length, offset);
+        
+       mcl[i].op = __HYPERVISOR_update_va_mapping_otherdomain;
+       mcl[i].args[0] = MMAP_VADDR(pending_idx, i) >> PAGE_SHIFT;
+        mcl[i].args[1] = ((buffer_mach & PAGE_MASK) + offset) | remap_prot;
+        mcl[i].args[2] = 0;
+        mcl[i].args[3] = up->domid;
+        
+        phys_to_machine_mapping[__pa(MMAP_VADDR(pending_idx, i))>>PAGE_SHIFT] =
+            FOREIGN_FRAME((buffer_mach + offset) >> PAGE_SHIFT);
+       //      printk("i = %d\n", i);
+
+        ASSERT(virt_to_machine(MMAP_VADDR(pending_idx, i))
+               == buffer_mach + i << PAGE_SHIFT);
+    }
+
+    if ( req->pipe_type == 0 && req->num_iso > 0 ) /* Maybe schedule ISO... */
+    {
+      //      printk("for iso, i = %d\n", i);
+        /* Map in ISO schedule, if necessary. */
+        mcl[i].op = __HYPERVISOR_update_va_mapping_otherdomain;
+        mcl[i].args[0] = MMAP_VADDR(pending_idx, i) >> PAGE_SHIFT;
+        mcl[i].args[1] = (req->iso_schedule & PAGE_MASK) | remap_prot;
+        mcl[i].args[2] = 0;
+        mcl[i].args[3] = up->domid;
+
+        phys_to_machine_mapping[__pa(MMAP_VADDR(pending_idx, i))>>PAGE_SHIFT] =
+            FOREIGN_FRAME(req->iso_schedule >> PAGE_SHIFT);
+    
+        //    printk("Mapped iso at %p\n", MMAP_VADDR(pending_idx, i));
+        i++;
+    }
+
+    //    printk("Well we got this far!\n");
+
+    if ( unlikely(HYPERVISOR_multicall(mcl, i) != 0) )
+        BUG();
+    
+    {
+        int j;
+        for ( j = 0; j < i; j++ )
+        {
+            if ( unlikely(mcl[j].args[5] != 0) )
+            {
+                printk("invalid buffer %d -- could not remap it\n", j);
+                fast_flush_area(pending_idx, i);
+               printk("sending invalid descriptor\n");
+                goto bad_descriptor;
+            }
+       }
+    }
+    
+ no_remap:
+
+    ASSERT(i <= MMAP_PAGES_PER_REQUEST);
+    ASSERT(i * PAGE_SIZE >= req->length);
+
+    /* We have to do this because some things might complete out of order. */
+    pending_req = &pending_reqs[pending_idx];
+    pending_req->usbif_priv= up;
+    pending_req->id        = req->id;
+    pending_req->operation = req->operation;
+    pending_req->nr_pages  = i;
+
+
+
+    pending_cons++;
+
+    usbif_get(up);
+    
+    /* Fill out an actual request for the USB layer. */
+    purb = usb_alloc_urb(req->num_iso);
+
+    if ( purb == NULL )
+        goto no_mem;
+
+    purb->dev = port->dev;
+    purb->context = pending_req;
+    purb->transfer_buffer = (void *)MMAP_VADDR(pending_idx, 0) + (buffer_mach & ~PAGE_MASK);
+    if(buffer_mach == 0)
+      purb->transfer_buffer = NULL;
+    purb->complete = __end_usb_io_op;
+    purb->transfer_buffer_length = req->length;
+    purb->transfer_flags = req->transfer_flags;
+
+/*     if ( req->transfer_flags != 0 ) */
+/*       dump_request(req); */
+
+    purb->pipe = 0;
+    purb->pipe |= req->direction << 7;
+    purb->pipe |= port->dev->devnum << 8;
+    purb->pipe |= req->speed << 26;
+    purb->pipe |= req->pipe_type << 30;
+    purb->pipe |= req->endpoint << 15;
+
+    purb->number_of_packets = req->num_iso;
+
+    /* Make sure there's always some kind of timeout. */
+    purb->timeout = ( req->timeout > 0 ) ?  (req->timeout * HZ) / 1000
+                    :  1000;
+
+    purb->setup_packet = setup;
+
+    if ( req->pipe_type == 0 ) /* ISO */
+    {
+        int j;
+        usbif_iso_t *iso_sched = (usbif_iso_t *)MMAP_VADDR(pending_idx, i - 1);
+
+       //      printk("Reading iso sched at %p\n", iso_sched);
+
+        /* If we're dealing with an iso pipe, we need to copy in a schedule. */
+        for ( j = 0; j < req->num_iso; j++ )
+        {
+            purb->iso_frame_desc[j].length = iso_sched[j].length;
+            purb->iso_frame_desc[j].offset = iso_sched[j].buffer_offset;
+            iso_sched[j].status = 0;
+        }
+        pending_req->iso_sched = iso_sched;
+    }
+
+    {
+      int ret;
+      ret = usb_submit_urb(purb);
+
+      //      dump_urb(purb);
+
+      if ( ret != 0 )
+          goto bad_descriptor; /* XXX free pending here! */
+    }
+    
+    return;
+
+ bad_descriptor:
+    kfree ( setup );
+    if ( purb != NULL )
+        usb_free_urb(purb);
+    make_response(up, req->id, req->operation, -EINVAL, 0, 0);
+    return;
+    
+ no_mem:
+    if ( setup != NULL )
+        kfree(setup);
+    make_response(up, req->id, req->operation, -ENOMEM, 0, 0);
+    return;
+} 
+
+
+
+/******************************************************************
+ * MISCELLANEOUS SETUP / TEARDOWN / DEBUGGING
+ */
+
+
+static void make_response(usbif_priv_t *up, unsigned long id,
+                          unsigned short op, int st, int inband,
+                         unsigned long length)
+{
+    usbif_response_t *resp;
+    unsigned long     flags;
+
+#if 0
+    printk("usbback: Sending response:\n");
+    printk("         id = 0x%x\n", id);
+    printk("         op = %d\n", op);
+    printk("         status = %d\n", st);
+    printk("         data = %d\n", inband);
+    printk("         length = %d\n", length);
+#endif
+
+    /* Place on the response ring for the relevant domain. */ 
+    spin_lock_irqsave(&up->usb_ring_lock, flags);
+    resp = &up->usb_ring_base->
+        ring[MASK_USBIF_IDX(up->usb_resp_prod)].resp;
+    resp->id        = id;
+    resp->operation = op;
+    resp->status    = st;
+    resp->data      = inband;
+    resp->length = length;
+    wmb(); /* Ensure other side can see the response fields. */
+    up->usb_ring_base->resp_prod = ++up->usb_resp_prod;
+    spin_unlock_irqrestore(&up->usb_ring_lock, flags);
+
+    /* Kick the relevant domain. */
+    notify_via_evtchn(up->evtchn);
+}
+
+/**
+ * usbif_claim_port - claim devices on a port on behalf of guest
+ *
+ * Once completed, this will ensure that any device attached to that
+ * port is claimed by this driver for use by the guest.
+ */
+int usbif_claim_port(usbif_be_claim_port_t *msg)
+{
+    owned_port_t *o_p;
+    
+    /* Sanity... */
+    if ( usbif_find_port(msg->path) != NULL )
+    {
+        printk("usbback: Attempted to claim USB port "
+               "we already own!\n");
+        return -EINVAL;
+    }
+
+    spin_lock_irq(&owned_ports_lock);
+    
+    /* No need for a slab cache - this should be infrequent. */
+    o_p = kmalloc(sizeof(owned_port_t), GFP_KERNEL);
+
+    o_p->enabled = 0;
+    o_p->usbif_priv = usbif_find(msg->domid);
+    o_p->guest_port = msg->usbif_port;
+    o_p->dev_present = 0;
+    o_p->guest_address = 0; /* Default address. */
+
+    strcpy(o_p->path, msg->path);
+
+    list_add(&o_p->list, &owned_ports);
+
+    printk("usbback: Claimed USB port (%s) for %d.%d\n", o_p->path,
+          msg->domid, msg->usbif_port);
+
+    spin_unlock_irq(&owned_ports_lock);
+
+    /* Force a reprobe for unclaimed devices. */
+    usb_scan_devices();
+
+    return 0;
+}
+
+owned_port_t *find_port_for_request(usbif_priv_t *up, usbif_request_t *req)
+{
+    unsigned long flags;
+    struct list_head *port;
+
+    /* I'm assuming this is not called from IRQ context - correct?  I think
+     * it's probably only called in response to control messages or plug events
+     * in the USB hub kernel thread, so should be OK. */
+    spin_lock_irqsave(&owned_ports_lock, flags);
+    list_for_each(port, &owned_ports)
+    {
+        owned_port_t *p = list_entry(port, owned_port_t, list);
+        if(p->usbif_priv == up && p->guest_address == req->devnum && p->enabled )
+         {
+#if 0
+              printk("Found port for devnum %d\n", req->devnum);
+
+              dump_port(p);
+#endif
+              return p;
+         }
+    }
+    spin_unlock_irqrestore(&owned_ports_lock, flags);
+
+    return NULL;    
+}
+
+owned_port_t *usbif_find_port(char *path)
+{
+    struct list_head *port;
+    unsigned long flags;
+
+    spin_lock_irqsave(&owned_ports_lock, flags);
+    list_for_each(port, &owned_ports)
+    {
+        owned_port_t *p = list_entry(port, owned_port_t, list);
+        if(!strcmp(path, p->path))
+        {
+            spin_unlock_irqrestore(&owned_ports_lock, flags);
+            return p;
+        }
+    }
+    spin_unlock_irqrestore(&owned_ports_lock, flags);
+
+    return NULL;
+}
+
+
+static void *probe(struct usb_device *dev, unsigned iface,
+           const struct usb_device_id *id)
+{
+    owned_port_t *p;
+
+    /* We don't care what the device is - if we own the port, we want it.  We
+     * don't deal with device-specifics in this driver, so we don't care what
+     * the device actually is ;-) */
+    if ( ( p = usbif_find_port(dev->devpath) ) != NULL )
+    {
+        printk("usbback: claimed device attached to owned port\n");
+
+        p->dev_present = 1;
+        p->dev = dev;
+        set_bit(iface, &p->ifaces);
+        
+        return p->usbif_priv;
+    }
+    else
+        printk("usbback: hotplug for non-owned port (%s), ignoring\n", dev->devpath);
+   
+
+    return NULL;
+}
+
+static void disconnect(struct usb_device *dev, void *usbif)
+{
+    /* Note the device is removed so we can tell the guest when it probes. */
+    owned_port_t *port = usbif_find_port(dev->devpath);
+    port->dev_present = 0;
+    port->dev = NULL;
+    port->ifaces = 0;
+}
+
+
+struct usb_driver driver =
+{
+    .owner      = THIS_MODULE,
+    .name       = "Xen USB Backend",
+    .probe      = probe,
+    .disconnect = disconnect,
+    .id_table   = NULL,
+};
+
+/* __usbif_release_port - internal mechanics for releasing a port */
+void __usbif_release_port(owned_port_t *p)
+{
+    int i;
+
+    for ( i = 0; p->ifaces != 0; i++)
+        if ( p->ifaces & 1 << i )
+        {
+            usb_driver_release_interface(&driver, usb_ifnum_to_if(p->dev, i));
+            clear_bit(i, &p->ifaces);
+        }
+    list_del(&p->list);
+
+    /* Reset the real device.  We don't simulate disconnect / probe for other
+     * drivers in this kernel because we assume the device is completely under
+     * the control of ourselves (i.e. the guest!).  This should ensure that the
+     * device is in a sane state for the next customer ;-) */
+/*     if ( p->dev != NULL) */
+/*         usb_reset_device(p->dev); */
+
+    kfree(p);
+}
+
+
+/**
+ * usbif_release_port - stop claiming devices on a port on behalf of guest
+ */
+void usbif_release_port(usbif_be_release_port_t *msg)
+{
+    owned_port_t *p;
+
+    spin_lock_irq(&owned_ports_lock);
+    p = usbif_find_port(msg->path);
+    __usbif_release_port(p);
+    spin_unlock_irq(&owned_ports_lock);
+}
+
+void usbif_release_ports(usbif_priv_t *up)
+{
+    struct list_head *port, *tmp;
+    unsigned long flags;
+    
+    spin_lock_irqsave(&owned_ports_lock, flags);
+    list_for_each_safe(port, tmp, &owned_ports)
+    {
+        owned_port_t *p = list_entry(port, owned_port_t, list);
+        if ( p->usbif_priv == up )
+            __usbif_release_port(p);
+    }
+    spin_unlock_irqrestore(&owned_ports_lock, flags);
+}
+
+static int __init usbif_init(void)
+{
+    int i;
+
+    if ( !(xen_start_info.flags & SIF_INITDOMAIN) &&
+         !(xen_start_info.flags & SIF_USB_BE_DOMAIN) )
+        return 0;
+    
+    INIT_LIST_HEAD(&owned_ports);
+
+    usb_register(&driver);
+
+    usbif_interface_init();
+
+    if ( (mmap_vstart = allocate_empty_lowmem_region(MMAP_PAGES)) == 0 )
+        BUG();
+
+    pending_cons = 0;
+    pending_prod = MAX_PENDING_REQS;
+    memset(pending_reqs, 0, sizeof(pending_reqs));
+    for ( i = 0; i < MAX_PENDING_REQS; i++ )
+        pending_ring[i] = i;
+
+    spin_lock_init(&usbio_schedule_list_lock);
+    INIT_LIST_HEAD(&usbio_schedule_list);
+
+    if ( kernel_thread(usbio_schedule, 0, CLONE_FS | CLONE_FILES) < 0 )
+        BUG();
+    
+    usbif_ctrlif_init();
+
+    spin_lock_init(&owned_ports_lock);
+
+    printk("Xen USB Backend Initialised");
+
+    return 0;
+}
+
+__initcall(usbif_init);
diff --git a/linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/frontend/Makefile b/linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/frontend/Makefile
new file mode 100644 (file)
index 0000000..032d02d
--- /dev/null
@@ -0,0 +1,3 @@
+O_TARGET := drv.o
+obj-y := main.o
+include $(TOPDIR)/Rules.make
diff --git a/linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/frontend/main.c b/linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/frontend/main.c
new file mode 100644 (file)
index 0000000..8cf879c
--- /dev/null
@@ -0,0 +1,1720 @@
+/*
+ * Xen Virtual USB Frontend Driver 
+ *
+ * This file contains the first version of the Xen virtual USB hub
+ * that I've managed not to delete by mistake (3rd time lucky!).
+ *
+ * Based on Linux's uhci.c, original copyright notices are displayed
+ * below.  Portions also (c) 2004 Intel Research Cambridge
+ * and (c) 2004 Mark Williamson
+ *
+ * Contact <mark.williamson@cl.cam.ac.uk> or
+ * <xen-devel@lists.sourceforge.net> regarding this code.
+ *
+ * Still to be (maybe) implemented:
+ * - multiple port
+ * - multiple interfaces
+ * - migration / backend restart support?
+ * - unloading support
+ *
+ * Differences to a normal host controller:
+ * - the backend does most of the mucky stuff so we don't have to do various
+ *   things that are necessary for a normal host controller (e.g. FSBR).
+ * - we don't have any hardware, so status registers are simulated in software.
+ */
+
+/*
+ * Universal Host Controller Interface driver for USB.
+ *
+ * Maintainer: Johannes Erdfelt <johannes@erdfelt.com>
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@erdfelt.com
+ * (C) Copyright 1999 Randy Dunlap
+ * (C) Copyright 1999 Georg Acher, acher@in.tum.de
+ * (C) Copyright 1999 Deti Fliegl, deti@fliegl.de
+ * (C) Copyright 1999 Thomas Sailer, sailer@ife.ee.ethz.ch
+ * (C) Copyright 1999 Roman Weissgaerber, weissg@vienna.at
+ * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
+ *               support from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
+ * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
+ *
+ * Intel documents this fairly well, and as far as I know there
+ * are no royalties or anything like that, but even so there are
+ * people who decided that they want to do the same thing in a
+ * completely different way.
+ *
+ * WARNING! The USB documentation is downright evil. Most of it
+ * is just crap, written by a committee. You're better off ignoring
+ * most of it, the important stuff is:
+ *  - the low-level protocol (fairly simple but lots of small details)
+ *  - working around the horridness of the rest
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#ifdef CONFIG_USB_DEBUG
+#define DEBUG
+#else
+#undef DEBUG
+#endif
+#include <linux/usb.h>
+
+#include <asm/uaccess.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+
+#include "xhci.h"
+
+#include <linux/pm.h>
+
+#include "../../../../../drivers/usb/hcd.h"
+
+#include "../usbif.h"
+#include <asm/ctrl_if.h>
+#include <asm/xen-public/io/domain_controller.h>
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v1.0"
+#define DRIVER_AUTHOR "Linus 'Frodo Rabbit' Torvalds, Johannes Erdfelt, Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber, Mark Williamson"
+#define DRIVER_DESC "Xen Virtual USB Host Controller Interface driver"
+
+/*
+ * debug = 0, no debugging messages
+ * debug = 1, dump failed URB's except for stalls
+ * debug = 2, dump all failed URB's (including stalls)
+ */
+#ifdef DEBUG
+static int debug = 1;
+#else
+static int debug = 0;
+#endif
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug level");
+static char *errbuf;
+#define ERRBUF_LEN    (PAGE_SIZE * 8)
+
+static kmem_cache_t *xhci_up_cachep;   /* urb_priv */
+
+static int rh_submit_urb(struct urb *urb);
+static int rh_unlink_urb(struct urb *urb);
+//static int xhci_get_current_frame_number(struct usb_device *dev);
+static int xhci_unlink_urb(struct urb *urb);
+static void xhci_unlink_generic(struct urb *urb);
+static void xhci_call_completion(struct urb *urb);
+static void xhci_drain_ring(void);
+
+#define MAX_URB_LOOP   2048            /* Maximum number of linked URB's */
+
+struct xhci *xhci;
+
+enum { USBIF_STATE_CONNECTED = 2,
+       USBIF_STATE_DISCONNECTED = 1,
+       USBIF_STATE_CLOSED =0
+};
+
+static int awaiting_reset = 0;
+
+/**
+ * xhci_construct_isoc - add isochronous information to a request
+ */
+int xhci_construct_isoc(usbif_request_t *req, struct urb *urb)
+{
+        usbif_iso_t *schedule;
+        int i;
+        struct urb_priv *urb_priv = urb->hcpriv;
+        
+        req->num_iso = urb->number_of_packets;
+        schedule = (usbif_iso_t *)__get_free_page(GFP_KERNEL);
+
+        if ( schedule == NULL )
+            return -ENOMEM;
+
+        for ( i = 0; i < req->num_iso; i++ )
+        {
+                schedule[i].buffer_offset = urb->iso_frame_desc[i].offset;
+                schedule[i].length = urb->iso_frame_desc[i].length;
+        }
+
+        urb_priv->schedule = schedule;
+       req->iso_schedule = virt_to_machine(schedule);
+
+        return 0;
+}
+
+#define USBIF_RING_FULL ((xhci->usbif->req_prod - xhci->usb_resp_cons) == USBIF_RING_SIZE)
+
+static void dump_urb(struct urb *urb)
+{
+        printk("dumping urb @ %p\n", urb);
+        
+        printk("hcpriv = %p\n", urb->hcpriv);
+        printk("next = %p\n", urb->next);
+        printk("dev = %p\n", urb->dev);
+        printk("pipe = 0x%lx\n", urb->pipe);
+        printk("status = %d\n", urb->status);
+        printk("transfer_flags = 0x%lx\n", urb->transfer_flags);
+        printk("transfer_buffer = %p\n", urb->transfer_buffer);
+        printk("transfer_buffer_length = %d\n", urb->transfer_buffer_length);
+        printk("actual_length = %d\n", urb->actual_length);
+        printk("bandwidth = %d\n", urb->bandwidth);
+        printk("setup_packet = %p\n", urb->setup_packet);
+       if ( urb->setup_packet != NULL )
+                 printk("setup = { 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n",
+               urb->setup_packet[0], urb->setup_packet[1], urb->setup_packet[2], urb->setup_packet[3],
+               urb->setup_packet[4], urb->setup_packet[5], urb->setup_packet[6], urb->setup_packet[7]);
+        printk("complete = %p\n", urb->complete);
+        printk("interval = %d\n", urb->interval);
+        
+}
+
+
+static int
+xhci_queue_req(struct urb *urb)
+{
+        usbif_request_t *req;
+        usbif_t *usbif = xhci->usbif;
+
+#if 0
+        printk("usbif = %p, req_prod = %d (@ 0x%lx), resp_prod = %d, resp_cons = %d\n",
+               usbif, usbif->req_prod, virt_to_machine(&usbif->req_prod),
+               usbif->resp_prod, xhci->usb_resp_cons);
+#endif
+        
+
+/*     printk("Usbif_priv %p, want IO at 0x%lx\n", urb->hcpriv, virt_to_machine(urb->transfer_buffer)); */
+
+        if ( USBIF_RING_FULL )
+        {
+                printk("xhci_queue_req(): USB ring full, not queuing request\n");
+                return -ENOBUFS;
+        }
+
+        /* Stick something in the shared communications ring. */
+        req = &usbif->ring[MASK_USBIF_IDX(usbif->req_prod)].req;
+
+        req->operation       = USBIF_OP_IO;
+        req->port            = 0; /* We don't care what the port is. */
+        req->id              = (unsigned long) urb->hcpriv;
+        req->transfer_buffer = virt_to_machine(urb->transfer_buffer);
+       req->devnum          = usb_pipedevice(urb->pipe);
+        req->direction       = usb_pipein(urb->pipe);
+       req->speed           = usb_pipeslow(urb->pipe);
+        req->pipe_type       = usb_pipetype(urb->pipe);
+        req->length          = urb->transfer_buffer_length;
+        req->transfer_flags  = urb->transfer_flags;
+       req->endpoint        = usb_pipeendpoint(urb->pipe);
+       req->speed           = usb_pipeslow(urb->pipe);
+       req->timeout         = urb->timeout * (1000 / HZ);
+
+        if ( usb_pipetype(urb->pipe) == 0 ) /* ISO */
+        {
+            int ret = xhci_construct_isoc(req, urb);
+            if ( ret != 0 )
+                return ret;
+        }
+
+       if(urb->setup_packet != NULL)
+                memcpy(req->setup, urb->setup_packet, 8);
+        else
+                memset(req->setup, 0, 8);
+        
+        wmb();
+
+        usbif->req_prod++;
+
+       notify_via_evtchn(xhci->evtchn);
+
+       //      dump_urb(urb);
+
+        return -EINPROGRESS;
+}
+
+static inline usbif_request_t *
+xhci_queue_probe(usbif_vdev_t port)
+{
+        usbif_request_t *req;
+        usbif_t *usbif = xhci->usbif;
+
+#if 0
+       printk("queuing probe: req_prod = %d (@ 0x%lx), resp_prod = %d, resp_cons = %d\n",
+              usbif->req_prod, virt_to_machine(&usbif->req_prod),
+              usbif->resp_prod, xhci->usb_resp_cons);
+#endif
+        
+        if ( USBIF_RING_FULL )
+        {
+                printk("xhci_queue_probe(): USB ring full, not queuing request\n");
+                return NULL;
+        }
+
+        /* Stick something in the shared communications ring. */
+        req = &usbif->ring[MASK_USBIF_IDX(usbif->req_prod)].req;
+
+        req->operation       = USBIF_OP_PROBE;
+        req->port            = port;
+        req->id              = 0;
+        req->transfer_buffer = 0;
+       req->devnum          = 0;
+        req->direction       = 0;
+       req->speed           = 0;
+        req->pipe_type       = 0;
+        req->length          = 0;
+        req->transfer_flags  = 0;
+       req->endpoint        = 0;
+       req->speed           = 0;
+
+        wmb();
+
+        usbif->req_prod++;
+
+       notify_via_evtchn(xhci->evtchn);
+
+        return req;
+}
+
+static int
+xhci_port_reset(usbif_vdev_t port)
+{
+        usbif_request_t *req;
+        usbif_t *usbif = xhci->usbif;
+
+        /* We only reset one port at a time, so we only need one variable per
+         * hub. */
+        awaiting_reset = 1;
+        
+        /* Stick something in the shared communications ring. */
+        req = &usbif->ring[MASK_USBIF_IDX(usbif->req_prod)].req;
+
+        req->operation       = USBIF_OP_RESET;
+        req->port            = port;
+        
+        wmb();
+
+        usbif->req_prod++;
+
+       notify_via_evtchn(xhci->evtchn);
+
+        while ( awaiting_reset > 0 )
+        {
+                mdelay(1);
+                xhci_drain_ring();
+        }
+
+        return awaiting_reset;
+}
+
+static void xhci_show_resp(usbif_response_t *r)
+{
+        printk("id=0x%lx, op=0x%x, data=0x%x, status=0x%x, length=0x%lx\n",
+               r->id, r->operation, r->data, r->status, r->length);
+}
+
+
+/*
+ * Only the USB core should call xhci_alloc_dev and xhci_free_dev
+ */
+static int xhci_alloc_dev(struct usb_device *dev)
+{
+       return 0;
+}
+
+static int xhci_free_dev(struct usb_device *dev)
+{
+       return 0;
+}
+
+static inline void xhci_add_complete(struct urb *urb)
+{
+       struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+       unsigned long flags;
+
+       spin_lock_irqsave(&xhci->complete_list_lock, flags);
+       list_add_tail(&urbp->complete_list, &xhci->complete_list);
+       spin_unlock_irqrestore(&xhci->complete_list_lock, flags);
+}
+
+/* When this returns, the owner of the URB may free its
+ * storage.
+ *
+ * We spin and wait for the URB to complete before returning.
+ */
+static void xhci_delete_urb(struct urb *urb)
+{
+        struct urb_priv *urbp;
+
+       urbp = urb->hcpriv;
+
+        /* If there's no urb_priv structure for this URB then it can't have
+         * been submitted at all. */
+       if ( urbp == NULL )
+               return;
+
+       /* For now we just spin until the URB completes.  It shouldn't take too
+         * long and we don't expect to have to do this very often. */
+       while ( urb->status == -EINPROGRESS )
+        {
+            xhci_drain_ring();
+            mdelay(1);
+        }
+
+       /* Now we know that further transfers to the buffer won't
+        * occur, so we can safely return. */
+}
+
+static struct urb_priv *xhci_alloc_urb_priv(struct urb *urb)
+{
+       struct urb_priv *urbp;
+
+       urbp = kmem_cache_alloc(xhci_up_cachep, SLAB_ATOMIC);
+       if (!urbp) {
+               err("xhci_alloc_urb_priv: couldn't allocate memory for urb_priv\n");
+               return NULL;
+       }
+
+       memset((void *)urbp, 0, sizeof(*urbp));
+
+       urbp->inserttime = jiffies;
+       urbp->urb = urb;
+       urbp->dev = urb->dev;
+       
+       INIT_LIST_HEAD(&urbp->complete_list);
+
+       urb->hcpriv = urbp;
+
+       return urbp;
+}
+
+/*
+ * MUST be called with urb->lock acquired
+ */
+/* When is this called?  Do we need to stop the transfer (as we
+ * currently do)? */
+static void xhci_destroy_urb_priv(struct urb *urb)
+{
+    struct urb_priv *urbp;
+    
+    urbp = (struct urb_priv *)urb->hcpriv;
+    if (!urbp)
+        return;
+
+    if (!list_empty(&urb->urb_list))
+        warn("xhci_destroy_urb_priv: urb %p still on xhci->urb_list or xhci->remove_list", urb);
+    
+    if (!list_empty(&urbp->complete_list))
+        warn("xhci_destroy_urb_priv: urb %p still on xhci->complete_list", urb);
+    
+    kmem_cache_free(xhci_up_cachep, urb->hcpriv);
+
+    urb->hcpriv = NULL;
+}
+
+/**
+ * Try to find URBs in progress on the same pipe to the same device.
+ *
+ * MUST be called with xhci->urb_list_lock acquired
+ */
+static struct urb *xhci_find_urb_ep(struct xhci *xhci, struct urb *urb)
+{
+       struct list_head *tmp, *head;
+
+       /* We don't match Isoc transfers since they are special */
+       if (usb_pipeisoc(urb->pipe))
+               return NULL;
+
+       head = &xhci->urb_list;
+       tmp = head->next;
+       while (tmp != head) {
+               struct urb *u = list_entry(tmp, struct urb, urb_list);
+
+               tmp = tmp->next;
+
+               if (u->dev == urb->dev && u->pipe == urb->pipe &&
+                   u->status == -EINPROGRESS)
+                       return u;
+       }
+
+       return NULL;
+}
+
+static int xhci_submit_urb(struct urb *urb)
+{
+       int ret = -EINVAL;
+       unsigned long flags;
+       struct urb *eurb;
+       int bustime;
+
+#if 0
+        printk("submitting urb @ %p for dev @ %p, devnum = %d path %s\n",
+               urb, urb->dev, urb->dev->devnum, urb->dev->devpath);
+#endif
+
+       if (!urb)
+               return -EINVAL;
+
+       if (!urb->dev || !urb->dev->bus || !urb->dev->bus->hcpriv) {
+               warn("xhci_submit_urb: urb %p belongs to disconnected device or bus?", urb);
+               return -ENODEV;
+       }
+
+        if ( urb->dev->devpath == NULL )
+        {
+                printk("BARF!\n");
+                BUG();
+        }
+        
+        
+
+       usb_inc_dev_use(urb->dev);
+
+       spin_lock_irqsave(&xhci->urb_list_lock, flags);
+       spin_lock(&urb->lock);
+
+       if (urb->status == -EINPROGRESS || urb->status == -ECONNRESET ||
+           urb->status == -ECONNABORTED) {
+               dbg("xhci_submit_urb: urb not available to submit (status = %d)", urb->status);
+               /* Since we can have problems on the out path */
+               spin_unlock(&urb->lock);
+               spin_unlock_irqrestore(&xhci->urb_list_lock, flags);
+               usb_dec_dev_use(urb->dev);
+
+               return ret;
+       }
+
+       INIT_LIST_HEAD(&urb->urb_list);
+       if (!xhci_alloc_urb_priv(urb)) {
+               ret = -ENOMEM;
+
+               goto out;
+       }
+
+        ( (struct urb_priv *)urb->hcpriv )->in_progress = 1;
+
+       eurb = xhci_find_urb_ep(xhci, urb);
+       if (eurb && !(urb->transfer_flags & USB_QUEUE_BULK)) {
+               ret = -ENXIO;
+
+               goto out;
+       }
+
+       /* Short circuit the virtual root hub */
+       if (urb->dev == xhci->rh.dev) {
+               ret = rh_submit_urb(urb);
+
+               goto out;
+       }
+
+       if ( usb_pipedevice(urb->pipe) == 1 )
+         printk("dev = %p, dev->path = %s, rh.dev = %p, rh.dev.devnum = %d rh.dev->path = %s!\n",
+                urb->dev, urb->dev->devpath, xhci->rh.dev, xhci->rh.dev->devnum, xhci->rh.dev->devpath);
+
+       switch (usb_pipetype(urb->pipe)) {
+       case PIPE_CONTROL:
+               ret = xhci_queue_req(urb);
+               break;
+       case PIPE_INTERRUPT:
+               if (urb->bandwidth == 0) {      /* not yet checked/allocated */
+                       bustime = usb_check_bandwidth(urb->dev, urb);
+                       if (bustime < 0)
+                               ret = bustime;
+                       else {
+                               ret = xhci_queue_req(urb);
+                               if (ret == -EINPROGRESS)
+                                       usb_claim_bandwidth(urb->dev, urb, bustime, 0);
+                       }
+               } else          /* bandwidth is already set */
+                       ret = xhci_queue_req(urb);
+               break;
+       case PIPE_BULK:
+               ret = xhci_queue_req(urb);
+               break;
+       case PIPE_ISOCHRONOUS:
+               if (urb->bandwidth == 0) {      /* not yet checked/allocated */
+                       if (urb->number_of_packets <= 0) {
+                               ret = -EINVAL;
+                               break;
+                       }
+                       bustime = usb_check_bandwidth(urb->dev, urb);
+                       if (bustime < 0) {
+                               ret = bustime;
+                               break;
+                       }
+
+                       ret = xhci_queue_req(urb);
+                       if (ret == -EINPROGRESS)
+                               usb_claim_bandwidth(urb->dev, urb, bustime, 1);
+               } else          /* bandwidth is already set */
+                       ret = xhci_queue_req(urb);
+               break;
+       }
+
+out:
+       urb->status = ret;
+
+       if (ret == -EINPROGRESS) {
+               /* We use _tail to make find_urb_ep more efficient */
+               list_add_tail(&urb->urb_list, &xhci->urb_list);
+
+               spin_unlock(&urb->lock);
+               spin_unlock_irqrestore(&xhci->urb_list_lock, flags);
+
+               return 0;
+       }
+
+       xhci_unlink_generic(urb);
+
+       spin_unlock(&urb->lock);
+       spin_unlock_irqrestore(&xhci->urb_list_lock, flags);
+
+       /* Only call completion if it was successful */
+       if (!ret)
+               xhci_call_completion(urb);
+
+       return ret;
+}
+
+/*
+ * Return the result of a transfer
+ *
+ * MUST be called with urb_list_lock acquired
+ */
+static void xhci_transfer_result(struct xhci *xhci, struct urb *urb)
+{
+       int ret = 0;
+       unsigned long flags;
+       struct urb_priv *urbp;
+
+       /* The root hub is special */
+       if (urb->dev == xhci->rh.dev)
+               return;
+
+       spin_lock_irqsave(&urb->lock, flags);
+
+       urbp = (struct urb_priv *)urb->hcpriv;
+
+        if ( ( (struct urb_priv *)urb->hcpriv )->in_progress )
+                ret = -EINPROGRESS;
+
+        if (urb->actual_length < urb->transfer_buffer_length) {
+                if (urb->transfer_flags & USB_DISABLE_SPD) {
+                        ret = -EREMOTEIO;
+                }
+        }
+
+       if (urb->status == -EPIPE)
+        {
+                ret = urb->status;
+               /* endpoint has stalled - mark it halted */
+               usb_endpoint_halt(urb->dev, usb_pipeendpoint(urb->pipe),
+                                  usb_pipeout(urb->pipe));
+        }
+
+       if ((debug == 1 && ret != 0 && ret != -EPIPE) ||
+            (ret != 0 && debug > 1)) {
+               /* Some debugging code */
+               dbg("xhci_result_interrupt/bulk() failed with status %x",
+                       status);
+       }
+
+       if (ret == -EINPROGRESS)
+               goto out;
+
+       switch (usb_pipetype(urb->pipe)) {
+       case PIPE_CONTROL:
+       case PIPE_BULK:
+       case PIPE_ISOCHRONOUS:
+               /* Release bandwidth for Interrupt or Isoc. transfers */
+               /* Spinlock needed ? */
+               if (urb->bandwidth)
+                       usb_release_bandwidth(urb->dev, urb, 1);
+               xhci_unlink_generic(urb);
+               break;
+       case PIPE_INTERRUPT:
+               /* Interrupts are an exception */
+               if (urb->interval)
+                       goto out_complete;
+
+               /* Release bandwidth for Interrupt or Isoc. transfers */
+               /* Spinlock needed ? */
+               if (urb->bandwidth)
+                       usb_release_bandwidth(urb->dev, urb, 0);
+               xhci_unlink_generic(urb);
+               break;
+       default:
+               info("xhci_transfer_result: unknown pipe type %d for urb %p\n",
+                       usb_pipetype(urb->pipe), urb);
+       }
+
+       /* Remove it from xhci->urb_list */
+       list_del_init(&urb->urb_list);
+
+out_complete:
+       xhci_add_complete(urb);
+
+out:
+       spin_unlock_irqrestore(&urb->lock, flags);
+}
+
+/*
+ * MUST be called with urb->lock acquired
+ */
+static void xhci_unlink_generic(struct urb *urb)
+{
+       struct urb_priv *urbp = urb->hcpriv;
+
+       /* We can get called when urbp allocation fails, so check */
+       if (!urbp)
+               return;
+
+        /* ??? This function is now so minimal it doesn't do much.  Do we really
+         * need it? */
+
+       xhci_delete_urb(urb);
+}
+
+static int xhci_unlink_urb(struct urb *urb)
+{
+       unsigned long flags;
+       struct urb_priv *urbp = urb->hcpriv;
+
+       if (!urb)
+               return -EINVAL;
+
+       if (!urb->dev || !urb->dev->bus || !urb->dev->bus->hcpriv)
+               return -ENODEV;
+
+       spin_lock_irqsave(&xhci->urb_list_lock, flags);
+       spin_lock(&urb->lock);
+
+       /* Release bandwidth for Interrupt or Isoc. transfers */
+       /* Spinlock needed ? */
+       if (urb->bandwidth) {
+               switch (usb_pipetype(urb->pipe)) {
+               case PIPE_INTERRUPT:
+                       usb_release_bandwidth(urb->dev, urb, 0);
+                       break;
+               case PIPE_ISOCHRONOUS:
+                       usb_release_bandwidth(urb->dev, urb, 1);
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       if (urb->status != -EINPROGRESS) {
+               spin_unlock(&urb->lock);
+               spin_unlock_irqrestore(&xhci->urb_list_lock, flags);
+               return 0;
+       }
+
+       list_del_init(&urb->urb_list);
+
+       xhci_unlink_generic(urb);
+
+       /* Short circuit the virtual root hub */
+       if (urb->dev == xhci->rh.dev) {
+               rh_unlink_urb(urb);
+
+               spin_unlock(&urb->lock);
+               spin_unlock_irqrestore(&xhci->urb_list_lock, flags);
+
+               xhci_call_completion(urb);
+       } else {
+               if (urb->transfer_flags & USB_ASYNC_UNLINK) {
+                       urbp->status = urb->status = -ECONNABORTED;
+
+                       spin_lock(&xhci->urb_remove_list_lock);
+
+                       list_add(&urb->urb_list, &xhci->urb_remove_list);
+
+                       spin_unlock(&xhci->urb_remove_list_lock);
+
+                       spin_unlock(&urb->lock);
+                       spin_unlock_irqrestore(&xhci->urb_list_lock, flags);
+
+               } else {
+                       urb->status = -ENOENT;
+
+                       spin_unlock(&urb->lock);
+                       spin_unlock_irqrestore(&xhci->urb_list_lock, flags);
+
+                       if (in_interrupt()) {   /* wait at least 1 frame */
+                               static int errorcount = 10;
+
+                               if (errorcount--)
+                                       dbg("xhci_unlink_urb called from interrupt for urb %p", urb);
+                               udelay(1000);
+                       } else
+                               schedule_timeout(1+1*HZ/1000); 
+
+                       xhci_call_completion(urb);
+               }
+       }
+
+       return 0;
+}
+
+
+struct usb_operations xhci_device_operations = {
+       .allocate = xhci_alloc_dev,
+       .deallocate = xhci_free_dev,
+        /* It doesn't look like any drivers actually care what the frame number
+        * is at the moment!  If necessary, we could approximate the current
+        * frame nubmer by passing it from the backend in response messages. */
+       .get_frame_number = NULL,
+       .submit_urb = xhci_submit_urb,
+       .unlink_urb = xhci_unlink_urb
+};
+
+/* Virtual Root Hub */
+
+static __u8 root_hub_dev_des[] =
+{
+       0x12,                   /*  __u8  bLength; */
+       0x01,                   /*  __u8  bDescriptorType; Device */
+       0x00,                   /*  __u16 bcdUSB; v1.0 */
+       0x01,
+       0x09,                   /*  __u8  bDeviceClass; HUB_CLASSCODE */
+       0x00,                   /*  __u8  bDeviceSubClass; */
+       0x00,                   /*  __u8  bDeviceProtocol; */
+       0x08,                   /*  __u8  bMaxPacketSize0; 8 Bytes */
+       0x00,                   /*  __u16 idVendor; */
+       0x00,
+       0x00,                   /*  __u16 idProduct; */
+       0x00,
+       0x00,                   /*  __u16 bcdDevice; */
+       0x00,
+       0x00,                   /*  __u8  iManufacturer; */
+       0x02,                   /*  __u8  iProduct; */
+       0x01,                   /*  __u8  iSerialNumber; */
+       0x01                    /*  __u8  bNumConfigurations; */
+};
+
+
+/* Configuration descriptor */
+static __u8 root_hub_config_des[] =
+{
+       0x09,                   /*  __u8  bLength; */
+       0x02,                   /*  __u8  bDescriptorType; Configuration */
+       0x19,                   /*  __u16 wTotalLength; */
+       0x00,
+       0x01,                   /*  __u8  bNumInterfaces; */
+       0x01,                   /*  __u8  bConfigurationValue; */
+       0x00,                   /*  __u8  iConfiguration; */
+       0x40,                   /*  __u8  bmAttributes;
+                                       Bit 7: Bus-powered, 6: Self-powered,
+                                       Bit 5 Remote-wakeup, 4..0: resvd */
+       0x00,                   /*  __u8  MaxPower; */
+
+       /* interface */
+       0x09,                   /*  __u8  if_bLength; */
+       0x04,                   /*  __u8  if_bDescriptorType; Interface */
+       0x00,                   /*  __u8  if_bInterfaceNumber; */
+       0x00,                   /*  __u8  if_bAlternateSetting; */
+       0x01,                   /*  __u8  if_bNumEndpoints; */
+       0x09,                   /*  __u8  if_bInterfaceClass; HUB_CLASSCODE */
+       0x00,                   /*  __u8  if_bInterfaceSubClass; */
+       0x00,                   /*  __u8  if_bInterfaceProtocol; */
+       0x00,                   /*  __u8  if_iInterface; */
+
+       /* endpoint */
+       0x07,                   /*  __u8  ep_bLength; */
+       0x05,                   /*  __u8  ep_bDescriptorType; Endpoint */
+       0x81,                   /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */
+       0x03,                   /*  __u8  ep_bmAttributes; Interrupt */
+       0x08,                   /*  __u16 ep_wMaxPacketSize; 8 Bytes */
+       0x00,
+       0xff                    /*  __u8  ep_bInterval; 255 ms */
+};
+
+static __u8 root_hub_hub_des[] =
+{
+       0x09,                   /*  __u8  bLength; */
+       0x29,                   /*  __u8  bDescriptorType; Hub-descriptor */
+       0x02,                   /*  __u8  bNbrPorts; */
+       0x00,                   /* __u16  wHubCharacteristics; */
+       0x00,
+       0x01,                   /*  __u8  bPwrOn2pwrGood; 2ms */
+       0x00,                   /*  __u8  bHubContrCurrent; 0 mA */
+       0x00,                   /*  __u8  DeviceRemovable; *** 7 Ports max *** */
+       0xff                    /*  __u8  PortPwrCtrlMask; *** 7 ports max *** */
+};
+
+/* prepare Interrupt pipe transaction data; HUB INTERRUPT ENDPOINT */
+static int rh_send_irq(struct urb *urb)
+{
+       struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+        xhci_port_t *ports = xhci->rh.ports;
+       unsigned long flags;
+       int i, len = 1;
+       __u16 data = 0;
+
+       spin_lock_irqsave(&urb->lock, flags);
+       for (i = 0; i < xhci->rh.numports; i++) {
+                /* MAW: No idea what the old code was doing here or why it worked.
+                * This implementation sets a bit if anything at all has changed on the 
+                * port, as per USB spec 11.12 */
+               data |= (ports[i].cs_chg || ports[i].pe_chg )
+                        ? (1 << (i + 1))
+                        : 0;
+
+               len = (i + 1) / 8 + 1;
+       }
+
+       *(__u16 *) urb->transfer_buffer = cpu_to_le16(data);
+       urb->actual_length = len;
+       urbp->status = 0;
+
+       spin_unlock_irqrestore(&urb->lock, flags);
+
+       if ((data > 0) && (xhci->rh.send != 0)) {
+               dbg("root-hub INT complete: data: %x", data);
+               xhci_call_completion(urb);
+       }
+
+       return 0;
+}
+
+/* Virtual Root Hub INTs are polled by this timer every "interval" ms */
+static int rh_init_int_timer(struct urb *urb);
+
+static void rh_int_timer_do(unsigned long ptr)
+{
+       struct urb *urb = (struct urb *)ptr;
+       struct list_head list, *tmp, *head;
+       unsigned long flags;
+       int i;
+
+       for ( i = 0; i < xhci->rh.numports; i++)
+                xhci_queue_probe(i);
+
+       if (xhci->rh.send)
+               rh_send_irq(urb);
+
+       INIT_LIST_HEAD(&list);
+
+       spin_lock_irqsave(&xhci->urb_list_lock, flags);
+       head = &xhci->urb_list;
+       tmp = head->next;
+       while (tmp != head) {
+               struct urb *u = list_entry(tmp, struct urb, urb_list);
+               struct urb_priv *up = (struct urb_priv *)u->hcpriv;
+
+               tmp = tmp->next;
+
+               spin_lock(&u->lock);
+
+               /* Check if the URB timed out */
+               if (u->timeout && time_after_eq(jiffies, up->inserttime + u->timeout)) {
+                       list_del(&u->urb_list);
+                       list_add_tail(&u->urb_list, &list);
+               }
+
+               spin_unlock(&u->lock);
+       }
+       spin_unlock_irqrestore(&xhci->urb_list_lock, flags);
+
+       head = &list;
+       tmp = head->next;
+       while (tmp != head) {
+               struct urb *u = list_entry(tmp, struct urb, urb_list);
+
+               tmp = tmp->next;
+
+               u->transfer_flags |= USB_ASYNC_UNLINK | USB_TIMEOUT_KILLED;
+               xhci_unlink_urb(u);
+       }
+
+       rh_init_int_timer(urb);
+}
+
+/* Root Hub INTs are polled by this timer */
+static int rh_init_int_timer(struct urb *urb)
+{
+       xhci->rh.interval = urb->interval;
+       init_timer(&xhci->rh.rh_int_timer);
+       xhci->rh.rh_int_timer.function = rh_int_timer_do;
+       xhci->rh.rh_int_timer.data = (unsigned long)urb;
+       xhci->rh.rh_int_timer.expires = jiffies + (HZ * (urb->interval < 30 ? 30 : urb->interval)) / 1000;
+       add_timer(&xhci->rh.rh_int_timer);
+
+       return 0;
+}
+
+#define OK(x)                  len = (x); break
+
+/* Root Hub Control Pipe */
+static int rh_submit_urb(struct urb *urb)
+{
+       unsigned int pipe = urb->pipe;
+       struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *)urb->setup_packet;
+       void *data = urb->transfer_buffer;
+       int leni = urb->transfer_buffer_length;
+       int len = 0;
+       xhci_port_t *status;
+       int stat = 0;
+       int i;
+       int retstatus;
+        unsigned long flags;
+        
+       __u16 cstatus;
+       __u16 bmRType_bReq;
+       __u16 wValue;
+       __u16 wIndex;
+       __u16 wLength;
+
+       if (usb_pipetype(pipe) == PIPE_INTERRUPT) {
+               xhci->rh.urb = urb;
+               xhci->rh.send = 1;
+               xhci->rh.interval = urb->interval;
+               rh_init_int_timer(urb);
+
+               return -EINPROGRESS;
+       }
+
+       bmRType_bReq = cmd->bRequestType | cmd->bRequest << 8;
+       wValue = le16_to_cpu(cmd->wValue);
+       wIndex = le16_to_cpu(cmd->wIndex);
+       wLength = le16_to_cpu(cmd->wLength);
+
+       for (i = 0; i < 8; i++)
+               xhci->rh.c_p_r[i] = 0;
+
+        status = &xhci->rh.ports[wIndex - 1];
+
+        spin_lock_irqsave(&xhci->rh.port_state_lock, flags);
+
+       switch (bmRType_bReq) {
+               /* Request Destination:
+                  without flags: Device,
+                  RH_INTERFACE: interface,
+                  RH_ENDPOINT: endpoint,
+                  RH_CLASS means HUB here,
+                  RH_OTHER | RH_CLASS  almost ever means HUB_PORT here
+               */
+
+       case RH_GET_STATUS:
+               *(__u16 *)data = cpu_to_le16(1);
+               OK(2);
+       case RH_GET_STATUS | RH_INTERFACE:
+               *(__u16 *)data = cpu_to_le16(0);
+               OK(2);
+       case RH_GET_STATUS | RH_ENDPOINT:
+               *(__u16 *)data = cpu_to_le16(0);
+               OK(2);
+       case RH_GET_STATUS | RH_CLASS:
+               *(__u32 *)data = cpu_to_le32(0);
+               OK(4);          /* hub power */
+       case RH_GET_STATUS | RH_OTHER | RH_CLASS:
+               cstatus = (status->cs_chg) |
+                       (status->pe_chg << 1) |
+                       (xhci->rh.c_p_r[wIndex - 1] << 4);
+               retstatus = (status->ccs) |
+                       (status->pe << 1) |
+                       (status->susp << 2) |
+                       (status->pr << 8) |
+                       (1 << 8) |      /* power on */
+                       (status->lsda << 9);
+               *(__u16 *)data = cpu_to_le16(retstatus);
+               *(__u16 *)(data + 2) = cpu_to_le16(cstatus);
+               OK(4);
+       case RH_CLEAR_FEATURE | RH_ENDPOINT:
+               switch (wValue) {
+               case RH_ENDPOINT_STALL:
+                       OK(0);
+               }
+               break;
+       case RH_CLEAR_FEATURE | RH_CLASS:
+               switch (wValue) {
+               case RH_C_HUB_OVER_CURRENT:
+                       OK(0);  /* hub power over current */
+               }
+               break;
+       case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+               switch (wValue) {
+               case RH_PORT_ENABLE:
+                        status->pe     = 0;
+                       OK(0);
+               case RH_PORT_SUSPEND:
+                        status->susp   = 0;
+                       OK(0);
+               case RH_PORT_POWER:
+                       OK(0);  /* port power */
+               case RH_C_PORT_CONNECTION:
+                        status->cs_chg = 0;
+                       OK(0);
+               case RH_C_PORT_ENABLE:
+                        status->pe_chg = 0;
+                       OK(0);
+               case RH_C_PORT_SUSPEND:
+                       /*** WR_RH_PORTSTAT(RH_PS_PSSC); */
+                       OK(0);
+               case RH_C_PORT_OVER_CURRENT:
+                       OK(0);  /* port power over current */
+               case RH_C_PORT_RESET:
+                       xhci->rh.c_p_r[wIndex - 1] = 0;
+                       OK(0);
+               }
+               break;
+       case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+               switch (wValue) {
+               case RH_PORT_SUSPEND:
+                        status->susp = 1;      
+                       OK(0);
+               case RH_PORT_RESET:
+                {
+                        int ret;
+                        xhci->rh.c_p_r[wIndex - 1] = 1;
+                        status->pr = 0;
+                        status->pe = 1;
+                        ret = xhci_port_reset(wIndex - 1);
+                        /* XXX MAW: should probably cancel queued transfers during reset... *\/ */
+                        if ( ret == 0 ) { OK(0); }
+                        else { return ret; }
+                }
+                break;
+               case RH_PORT_POWER:
+                       OK(0); /* port power ** */
+               case RH_PORT_ENABLE:
+                        status->pe = 1;
+                       OK(0);
+               }
+               break;
+       case RH_SET_ADDRESS:
+         printk("setting root hub device to %d\n", wValue);
+               xhci->rh.devnum = wValue;
+               OK(0);
+       case RH_GET_DESCRIPTOR:
+               switch ((wValue & 0xff00) >> 8) {
+               case 0x01:      /* device descriptor */
+                       len = min_t(unsigned int, leni,
+                                 min_t(unsigned int,
+                                     sizeof(root_hub_dev_des), wLength));
+                       memcpy(data, root_hub_dev_des, len);
+                       OK(len);
+               case 0x02:      /* configuration descriptor */
+                       len = min_t(unsigned int, leni,
+                                 min_t(unsigned int,
+                                     sizeof(root_hub_config_des), wLength));
+                       memcpy (data, root_hub_config_des, len);
+                       OK(len);
+               case 0x03:      /* string descriptors */
+                       len = usb_root_hub_string (wValue & 0xff,
+                               0, "XHCI-alt",
+                               data, wLength);
+                       if (len > 0) {
+                               OK(min_t(int, leni, len));
+                       } else 
+                               stat = -EPIPE;
+               }
+               break;
+       case RH_GET_DESCRIPTOR | RH_CLASS:
+               root_hub_hub_des[2] = xhci->rh.numports;
+               len = min_t(unsigned int, leni,
+                         min_t(unsigned int, sizeof(root_hub_hub_des), wLength));
+               memcpy(data, root_hub_hub_des, len);
+               OK(len);
+       case RH_GET_CONFIGURATION:
+               *(__u8 *)data = 0x01;
+               OK(1);
+       case RH_SET_CONFIGURATION:
+               OK(0);
+       case RH_GET_INTERFACE | RH_INTERFACE:
+               *(__u8 *)data = 0x00;
+               OK(1);
+       case RH_SET_INTERFACE | RH_INTERFACE:
+               OK(0);
+       default:
+               stat = -EPIPE;
+       }
+
+        spin_unlock_irqrestore(&xhci->rh.port_state_lock, flags);
+
+       urb->actual_length = len;
+
+       return stat;
+}
+
+/*
+ * MUST be called with urb->lock acquired
+ */
+static int rh_unlink_urb(struct urb *urb)
+{
+       if (xhci->rh.urb == urb) {
+               urb->status = -ENOENT;
+               xhci->rh.send = 0;
+               xhci->rh.urb = NULL;
+               del_timer(&xhci->rh.rh_int_timer);
+       }
+       return 0;
+}
+
+static void xhci_call_completion(struct urb *urb)
+{
+       struct urb_priv *urbp;
+       struct usb_device *dev = urb->dev;
+       int is_ring = 0, killed, resubmit_interrupt, status;
+       struct urb *nurb;
+       unsigned long flags;
+
+       spin_lock_irqsave(&urb->lock, flags);
+
+       urbp = (struct urb_priv *)urb->hcpriv;
+       if (!urbp || !urb->dev) {
+               spin_unlock_irqrestore(&urb->lock, flags);
+               return;
+       }
+
+       killed = (urb->status == -ENOENT || urb->status == -ECONNABORTED ||
+                       urb->status == -ECONNRESET);
+       resubmit_interrupt = (usb_pipetype(urb->pipe) == PIPE_INTERRUPT &&
+                       urb->interval);
+
+       nurb = urb->next;
+       if (nurb && !killed) {
+               int count = 0;
+
+               while (nurb && nurb != urb && count < MAX_URB_LOOP) {
+                       if (nurb->status == -ENOENT ||
+                           nurb->status == -ECONNABORTED ||
+                           nurb->status == -ECONNRESET) {
+                               killed = 1;
+                               break;
+                       }
+
+                       nurb = nurb->next;
+                       count++;
+               }
+
+               if (count == MAX_URB_LOOP)
+                       err("xhci_call_completion: too many linked URB's, loop? (first loop)");
+
+               /* Check to see if chain is a ring */
+               is_ring = (nurb == urb);
+       }
+
+       status = urbp->status;
+       if (!resubmit_interrupt || killed)
+               /* We don't need urb_priv anymore */
+               xhci_destroy_urb_priv(urb);
+
+       if (!killed)
+               urb->status = status;
+
+       spin_unlock_irqrestore(&urb->lock, flags);
+
+       if (urb->complete)
+               urb->complete(urb);
+
+       if (resubmit_interrupt)
+               /* Recheck the status. The completion handler may have */
+               /*  unlinked the resubmitting interrupt URB */
+               killed = (urb->status == -ENOENT ||
+                         urb->status == -ECONNABORTED ||
+                         urb->status == -ECONNRESET);
+
+       if (resubmit_interrupt && !killed) {
+                if ( urb->dev != xhci->rh.dev )
+                        xhci_queue_req(urb); /* XXX What if this fails? */
+                /* Don't need to resubmit URBs for the virtual root dev. */
+       } else {
+               if (is_ring && !killed) {
+                       urb->dev = dev;
+                       xhci_submit_urb(urb);
+               } else {
+                       /* We decrement the usage count after we're done */
+                       /*  with everything */
+                       usb_dec_dev_use(dev);
+               }
+       }
+}
+
+static void xhci_finish_completion(void)
+{
+       struct list_head *tmp, *head;
+       unsigned long flags;
+
+       spin_lock_irqsave(&xhci->complete_list_lock, flags);
+       head = &xhci->complete_list;
+       tmp = head->next;
+       while (tmp != head) {
+               struct urb_priv *urbp = list_entry(tmp, struct urb_priv, complete_list);
+               struct urb *urb = urbp->urb;
+
+               list_del_init(&urbp->complete_list);
+               spin_unlock_irqrestore(&xhci->complete_list_lock, flags);
+
+               xhci_call_completion(urb);
+
+               spin_lock_irqsave(&xhci->complete_list_lock, flags);
+               head = &xhci->complete_list;
+               tmp = head->next;
+       }
+       spin_unlock_irqrestore(&xhci->complete_list_lock, flags);
+}
+
+void receive_usb_reset(usbif_response_t *resp)
+{
+    awaiting_reset = resp->status;
+    rmb();
+    
+}
+
+void receive_usb_probe(usbif_response_t *resp)
+{
+    spin_lock(&xhci->rh.port_state_lock);
+
+    if ( resp->status > 0 )
+    {
+        if ( resp->status == 1 )
+        {
+/*       printk("hey hey, there's a device on port %d\n", resp->data); */
+
+            /* If theres a device there and there wasn't one before there must
+             * have been a connection status change. */
+            if( xhci->rh.ports[resp->data].cs == 0 )
+           {
+                xhci->rh.ports[resp->data].cs = 1;
+                xhci->rh.ports[resp->data].ccs = 1;
+                xhci->rh.ports[resp->data].cs_chg = 1;
+/*             printk("Look at device on port %d that wasn't there before\n", resp->data); */
+           }
+        }
+        else
+            printk("receive_usb_probe(): unexpected status %d for port %d\n",
+                   resp->status, resp->data);
+    }
+    else if ( resp->status < 0)
+        printk("receive_usb_probe(): got error status %d\n", resp->status);
+
+    spin_unlock(&xhci->rh.port_state_lock);
+}
+
+void receive_usb_io(usbif_response_t *resp)
+{
+        struct urb_priv *urbp = (struct urb_priv *)resp->id;
+        struct urb *urb = urbp->urb;
+
+        urb->actual_length = resp->length;
+       urb->status = resp->status;
+       urbp->status = resp->status;
+        urbp->in_progress = 0;
+
+        if( usb_pipetype(urb->pipe) == 0 ) /* ISO */
+        {
+                int i;
+              
+                /* Copy ISO schedule results back in. */
+
+                for ( i = 0; i < urb->number_of_packets; i++ )
+                {
+                        urb->iso_frame_desc[i].status
+                         = urbp->schedule[i].status;
+                        urb->iso_frame_desc[i].actual_length
+                                = urbp->schedule[i].length;
+                }
+                free_page((unsigned long)urbp->schedule);
+        }
+}
+
+static void xhci_drain_ring(void)
+{
+       struct list_head *tmp, *head;
+       usbif_t *usb_ring = xhci->usbif;
+       usbif_response_t *resp;
+        USBIF_RING_IDX i, rp;
+
+        /* Walk the ring here to get responses, updating URBs to show what
+         * completed. */
+        
+        rp = usb_ring->resp_prod;
+        rmb(); /* Ensure we see queued requests up to 'rp'. */
+
+        /* Take items off the comms ring, taking care not to overflow. */
+        for ( i = xhci->usb_resp_cons; 
+              (i != rp) && ((i-usb_ring->req_prod) != USBIF_RING_SIZE);
+              i++ )
+        {
+            resp = &usb_ring->ring[MASK_USBIF_IDX(i)].resp;
+            
+            /* May need to deal with batching and with putting a ceiling on
+               the number dispatched for performance and anti-dos reasons */
+
+#if 0
+            printk("usbfront: Processing response:\n");
+            printk("          id = 0x%x\n", resp->id);
+            printk("          op = %d\n", resp->operation);
+            printk("          status = %d\n", resp->status);
+            printk("          length = %d\n", resp->length);
+#endif            
+
+            switch ( resp->operation )
+            {
+            case USBIF_OP_PROBE:
+                receive_usb_probe(resp);
+                break;
+                
+            case USBIF_OP_IO:
+                receive_usb_io(resp);
+                break;
+
+            case USBIF_OP_RESET:
+                receive_usb_reset(resp);
+                break;
+
+            default:
+                printk("error: unknown USB io operation response [%d]\n",
+                       usb_ring->ring[i].req.operation);
+                break;
+            }
+        }
+
+        xhci->usb_resp_cons = i;
+
+       /* Walk the list of pending URB's to see which ones completed and do
+         * callbacks, etc. */
+       spin_lock(&xhci->urb_list_lock);
+       head = &xhci->urb_list;
+       tmp = head->next;
+       while (tmp != head) {
+                
+               struct urb *urb = list_entry(tmp, struct urb, urb_list);
+
+               tmp = tmp->next;
+
+               /* Checks the status and does all of the magic necessary */
+               xhci_transfer_result(xhci, urb);
+       }
+       spin_unlock(&xhci->urb_list_lock);
+
+       xhci_finish_completion();
+}
+
+
+static void xhci_interrupt(int irq, void *__xhci, struct pt_regs *regs)
+{
+        xhci_drain_ring();
+}
+
+static void free_xhci(struct xhci *xhci)
+{
+       kfree(xhci);
+}
+
+/* /\* */
+/*  * De-allocate all resources.. */
+/*  *\/ */
+/* static void release_xhci(struct xhci *xhci) */
+/* { */
+/*     if (xhci->irq >= 0) { */
+/*             free_irq(xhci->irq, xhci); */
+/*             xhci->irq = -1; */
+/*     } */
+
+/*         /\* Get the ring back from the backend domain.  Then free it.  Hmmmm. */
+/*          * Lets ignore this for now - not particularly useful. *\/ */
+
+/*     free_xhci(xhci); */
+/* } */
+
+/**
+ * Initialise a new virtual root hub for a new USB device channel.
+ */
+static int alloc_xhci(void)
+{
+       int retval;
+       struct usb_bus *bus;
+
+       retval = -EBUSY;
+
+       xhci = kmalloc(sizeof(*xhci), GFP_KERNEL);
+       if (!xhci) {
+               err("couldn't allocate xhci structure");
+               retval = -ENOMEM;
+               goto err_alloc_xhci;
+       }
+
+       /* Reset here so we don't get any interrupts from an old setup */
+       /*  or broken setup */
+       //      reset_hc(xhci);
+
+
+       xhci->state = USBIF_STATE_CLOSED;
+       xhci->is_suspended = 0;
+
+       spin_lock_init(&xhci->urb_remove_list_lock);
+       INIT_LIST_HEAD(&xhci->urb_remove_list);
+
+       spin_lock_init(&xhci->urb_list_lock);
+       INIT_LIST_HEAD(&xhci->urb_list);
+
+       spin_lock_init(&xhci->complete_list_lock);
+       INIT_LIST_HEAD(&xhci->complete_list);
+
+       spin_lock_init(&xhci->frame_list_lock);
+
+       /* We need exactly one page (per XHCI specs), how convenient */
+       /* We assume that one page is atleast 4k (1024 frames * 4 bytes) */
+#if PAGE_SIZE < (4 * 1024)
+#error PAGE_SIZE is not atleast 4k
+#endif
+       bus = usb_alloc_bus(&xhci_device_operations);
+       if (!bus) {
+               err("unable to allocate bus");
+               goto err_alloc_bus;
+       }
+
+       xhci->bus = bus;
+       bus->bus_name = "XHCI";
+       bus->hcpriv = xhci;
+
+       usb_register_bus(xhci->bus);
+
+       /* Initialize the root hub */
+
+       xhci->rh.numports = 0;
+
+       xhci->bus->root_hub = xhci->rh.dev = usb_alloc_dev(NULL, xhci->bus);
+       if (!xhci->rh.dev) {
+               err("unable to allocate root hub");
+               goto err_alloc_root_hub;
+       }
+
+       xhci->state = 0;
+
+       return 0;
+
+/*
+ * error exits:
+ */
+err_start_root_hub:
+       free_irq(xhci->irq, xhci);
+       xhci->irq = -1;
+
+err_alloc_root_hub:
+       usb_free_bus(xhci->bus);
+       xhci->bus = NULL;
+
+err_alloc_bus:
+       free_xhci(xhci);
+
+err_alloc_xhci:
+       return retval;
+}
+
+static void usbif_status_change(usbif_fe_interface_status_changed_t *status)
+{
+    ctrl_msg_t                   cmsg;
+    usbif_fe_interface_connect_t up;
+    long rc;
+    usbif_t *usbif;
+
+    switch ( status->status )
+    {
+    case USBIF_INTERFACE_STATUS_DESTROYED:
+        printk(KERN_WARNING "Unexpected usbif-DESTROYED message in state %d\n",
+               xhci->state);
+        break;
+
+    case USBIF_INTERFACE_STATUS_DISCONNECTED:
+        if ( xhci->state != USBIF_STATE_CLOSED )
+        {
+            printk(KERN_WARNING "Unexpected usbif-DISCONNECTED message"
+                   " in state %d\n", xhci->state);
+            break;
+            /* Not bothering to do recovery here for now.  Keep things
+             * simple. */
+        }
+
+        /* Move from CLOSED to DISCONNECTED state. */
+        xhci->usbif = usbif = (usbif_t *)__get_free_page(GFP_KERNEL);
+        usbif->req_prod = usbif->resp_prod = 0;
+        xhci->state  = USBIF_STATE_DISCONNECTED;
+
+        /* Construct an interface-CONNECT message for the domain controller. */
+        cmsg.type      = CMSG_USBIF_FE;
+        cmsg.subtype   = CMSG_USBIF_FE_INTERFACE_CONNECT;
+        cmsg.length    = sizeof(usbif_fe_interface_connect_t);
+        up.shmem_frame = virt_to_machine(usbif) >> PAGE_SHIFT;
+        memcpy(cmsg.msg, &up, sizeof(up));
+        
+        /* Tell the controller to bring up the interface. */
+        ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
+        break;
+
+    case USBIF_INTERFACE_STATUS_CONNECTED:
+        if ( xhci->state == USBIF_STATE_CLOSED )
+        {
+            printk(KERN_WARNING "Unexpected usbif-CONNECTED message"
+                   " in state %d\n", xhci->state);
+            break;
+        }
+
+        xhci->evtchn = status->evtchn;
+        xhci->irq = bind_evtchn_to_irq(xhci->evtchn);
+       xhci->bandwidth = status->bandwidth;
+       xhci->rh.numports = status->num_ports;
+
+        xhci->rh.ports = kmalloc (sizeof(xhci_port_t) * xhci->rh.numports, GFP_KERNEL);
+        memset(xhci->rh.ports, 0, sizeof(xhci_port_t) * xhci->rh.numports);
+
+        printk("rh.dev @ %p\n", xhci->rh.dev);
+
+       usb_connect(xhci->rh.dev);
+
+       if (usb_new_device(xhci->rh.dev) != 0) {
+               err("unable to start root hub");
+       }
+
+       /* Allocate the appropriate USB bandwidth here...  Need to
+       * somehow know what the total available is thought to be so we
+       * can calculate the reservation correctly. */
+       usb_claim_bandwidth(xhci->rh.dev, xhci->rh.urb,
+                           1000 - xhci->bandwidth, 0);
+
+        if ( (rc = request_irq(xhci->irq, xhci_interrupt, 
+                               SA_SAMPLE_RANDOM, "usbif", xhci)) )
+                printk(KERN_ALERT"usbfront request_irq failed (%ld)\n",rc);
+
+       printk(KERN_INFO __FILE__ ": USB XHCI: SHM at %p (0x%lx), EVTCHN %d IRQ %d\n",
+               xhci->usbif, virt_to_machine(xhci->usbif), xhci->evtchn, xhci->irq);
+
+        xhci->state = USBIF_STATE_CONNECTED;
+        
+        break;
+
+    default:
+        printk(KERN_WARNING "Status change to unknown value %d\n", 
+               status->status);
+        break;
+    }
+}
+
+
+static void usbif_ctrlif_rx(ctrl_msg_t *msg, unsigned long id)
+{
+    switch ( msg->subtype )
+    {
+    case CMSG_USBIF_FE_INTERFACE_STATUS_CHANGED:
+        if ( msg->length != sizeof(usbif_fe_interface_status_changed_t) )
+            goto parse_error;
+        usbif_status_change((usbif_fe_interface_status_changed_t *)
+                            &msg->msg[0]);
+        break;        
+
+        /* New interface...? */
+    default:
+        goto parse_error;
+    }
+
+    ctrl_if_send_response(msg);
+    return;
+
+ parse_error:
+    msg->length = 0;
+    ctrl_if_send_response(msg);
+}
+
+
+static int __init xhci_hcd_init(void)
+{
+       int retval = -ENOMEM, i;
+        usbif_fe_interface_status_changed_t st;
+        control_msg_t cmsg;
+
+       if ( (xen_start_info.flags & SIF_INITDOMAIN)
+            || (xen_start_info.flags & SIF_USB_BE_DOMAIN) )
+                return 0;
+
+       info(DRIVER_DESC " " DRIVER_VERSION);
+
+       if (debug) {
+               errbuf = kmalloc(ERRBUF_LEN, GFP_KERNEL);
+               if (!errbuf)
+                       goto errbuf_failed;
+       }
+
+       xhci_up_cachep = kmem_cache_create("xhci_urb_priv",
+               sizeof(struct urb_priv), 0, 0, NULL, NULL);
+       if (!xhci_up_cachep)
+               goto up_failed;
+
+        /* Lazily avoid unloading issues for now. ;-)*/
+       MOD_INC_USE_COUNT;
+
+        /* Let the domain controller know we're here.  For now we wait until
+         * connection, as for the block and net drivers.  This is only strictly
+         * necessary if we're going to boot off a USB device. */
+        printk(KERN_INFO "Initialising Xen virtual USB hub\n");
+    
+        (void)ctrl_if_register_receiver(CMSG_USBIF_FE, usbif_ctrlif_rx,
+                                        CALLBACK_IN_BLOCKING_CONTEXT);
+        
+       alloc_xhci();
+
+        /* Send a driver-UP notification to the domain controller. */
+        cmsg.type      = CMSG_USBIF_FE;
+        cmsg.subtype   = CMSG_USBIF_FE_DRIVER_STATUS_CHANGED;
+        cmsg.length    = sizeof(usbif_fe_driver_status_changed_t);
+        st.status      = USBIF_DRIVER_STATUS_UP;
+        memcpy(cmsg.msg, &st, sizeof(st));
+        ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
+        
+        /*
+         * We should read 'nr_interfaces' from response message and wait
+         * for notifications before proceeding. For now we assume that we
+         * will be notified of exactly one interface.
+         */
+        for ( i=0; (xhci->state != USBIF_STATE_CONNECTED) && (i < 10*HZ); i++ )
+        {
+            set_current_state(TASK_INTERRUPTIBLE);
+            schedule_timeout(1);
+        }
+        
+        if (xhci->state != USBIF_STATE_CONNECTED)
+            printk(KERN_INFO "Timeout connecting USB frontend driver!\n");
+       
+       return 0;
+
+up_failed:
+
+       if (errbuf)
+               kfree(errbuf);
+
+errbuf_failed:
+
+       return retval;
+}
+
+static void __exit xhci_hcd_cleanup(void) 
+{
+       if (kmem_cache_destroy(xhci_up_cachep))
+               printk(KERN_INFO "xhci: not all urb_priv's were freed\n");
+
+//        release_xhci(); do some calls here
+
+
+       if (errbuf)
+               kfree(errbuf);
+}
+
+module_init(xhci_hcd_init);
+module_exit(xhci_hcd_cleanup);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
diff --git a/linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/frontend/xhci.h b/linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/frontend/xhci.h
new file mode 100644 (file)
index 0000000..4be67b9
--- /dev/null
@@ -0,0 +1,210 @@
+#ifndef __LINUX_XHCI_H
+#define __LINUX_XHCI_H
+
+#include <linux/list.h>
+#include <linux/usb.h>
+#include "../usbif.h"
+#include <linux/spinlock.h>
+
+#define XHCI_NUMFRAMES         1024    /* in the frame list [array] */
+#define XHCI_MAX_SOF_NUMBER    2047    /* in an SOF packet */
+#define CAN_SCHEDULE_FRAMES    1000    /* how far future frames can be scheduled */
+
+/* In the absence of actual hardware state, we maintain the current known state
+ * of the virtual hub ports in this data structure.
+ */
+typedef struct
+{
+        unsigned int cs     :1;     /* Connection status.  do we really need this /and/ ccs? */
+        unsigned int cs_chg :1; /* Connection status change.  */
+        unsigned int pe     :1;     /* Port enable.               */
+        unsigned int pe_chg :1; /* Port enable change.        */
+        unsigned int ccs    :1;    /* Current connect status.    */
+        unsigned int susp   :1;   /* Suspended.                 */
+        unsigned int lsda   :1;   /* Low speed device attached. */
+        unsigned int pr     :1;     /* Port reset.                */
+        
+    /* Device info? */
+} xhci_port_t;
+
+struct xhci_frame_list {
+       __u32 frame[XHCI_NUMFRAMES];
+
+       void *frame_cpu[XHCI_NUMFRAMES];
+};
+
+struct urb_priv;
+
+#define xhci_status_bits(ctrl_sts)     (ctrl_sts & 0xFE0000)
+#define xhci_actual_length(ctrl_sts)   ((ctrl_sts + 1) & TD_CTRL_ACTLEN_MASK) /* 1-based */
+
+#define xhci_maxlen(token)     ((token) >> 21)
+#define xhci_expected_length(info) (((info >> 21) + 1) & TD_TOKEN_EXPLEN_MASK) /* 1-based */
+#define xhci_toggle(token)     (((token) >> TD_TOKEN_TOGGLE_SHIFT) & 1)
+#define xhci_endpoint(token)   (((token) >> 15) & 0xf)
+#define xhci_devaddr(token)    (((token) >> 8) & 0x7f)
+#define xhci_devep(token)      (((token) >> 8) & 0x7ff)
+#define xhci_packetid(token)   ((token) & TD_TOKEN_PID_MASK)
+#define xhci_packetout(token)  (xhci_packetid(token) != USB_PID_IN)
+#define xhci_packetin(token)   (xhci_packetid(token) == USB_PID_IN)
+
+struct virt_root_hub {
+       struct usb_device *dev;
+       int devnum;             /* Address of Root Hub endpoint */
+       struct urb *urb;
+       void *int_addr;
+       int send;
+       int interval;
+       int numports;
+       int c_p_r[8];
+       struct timer_list rh_int_timer;
+        spinlock_t port_state_lock;
+        xhci_port_t *ports;       /*  */
+};
+
+/*
+ * This describes the full xhci information.
+ *
+ * Note how the "proper" USB information is just
+ * a subset of what the full implementation needs.
+ */
+struct xhci {
+
+#ifdef CONFIG_PROC_FS
+       /* procfs */
+       int num;
+       struct proc_dir_entry *proc_entry;
+#endif
+
+        int evtchn;                        /* Interdom channel to backend */
+        int irq;                           /* Bound to evtchn */
+        int state;                         /* State of this USB interface */
+        unsigned long bandwidth;
+        int handle;
+
+       struct usb_bus *bus;
+
+       spinlock_t frame_list_lock;
+       struct xhci_frame_list *fl;             /* P: xhci->frame_list_lock */
+       int is_suspended;
+
+       /* Main list of URB's currently controlled by this HC */
+       spinlock_t urb_list_lock;
+       struct list_head urb_list;              /* P: xhci->urb_list_lock */
+
+       /* List of asynchronously unlinked URB's */
+       spinlock_t urb_remove_list_lock;
+       struct list_head urb_remove_list;       /* P: xhci->urb_remove_list_lock */
+
+       /* List of URB's awaiting completion callback */
+       spinlock_t complete_list_lock;
+       struct list_head complete_list;         /* P: xhci->complete_list_lock */
+
+       struct virt_root_hub rh;        /* private data of the virtual root hub */
+
+        spinlock_t response_lock;
+
+        usbif_t *usbif;
+        int usb_resp_cons;
+};
+
+struct urb_priv {
+       struct urb *urb;
+        usbif_iso_t *schedule;
+       struct usb_device *dev;
+
+        int in_progress : 1;           /* QH was queued (not linked in) */
+       int short_control_packet : 1;   /* If we get a short packet during */
+                                       /*  a control transfer, retrigger */
+                                       /*  the status phase */
+
+       int status;                     /* Final status */
+
+       unsigned long inserttime;       /* In jiffies */
+
+       struct list_head queue_list;    /* P: xhci->frame_list_lock */
+       struct list_head complete_list; /* P: xhci->complete_list_lock */
+};
+
+/*
+ * Locking in xhci.c
+ *
+ * spinlocks are used extensively to protect the many lists and data
+ * structures we have. It's not that pretty, but it's necessary. We
+ * need to be done with all of the locks (except complete_list_lock) when
+ * we call urb->complete. I've tried to make it simple enough so I don't
+ * have to spend hours racking my brain trying to figure out if the
+ * locking is safe.
+ *
+ * Here's the safe locking order to prevent deadlocks:
+ *
+ * #1 xhci->urb_list_lock
+ * #2 urb->lock
+ * #3 xhci->urb_remove_list_lock, xhci->frame_list_lock, 
+ *   xhci->qh_remove_list_lock
+ * #4 xhci->complete_list_lock
+ *
+ * If you're going to grab 2 or more locks at once, ALWAYS grab the lock
+ * at the lowest level FIRST and NEVER grab locks at the same level at the
+ * same time.
+ * 
+ * So, if you need xhci->urb_list_lock, grab it before you grab urb->lock
+ */
+
+/* -------------------------------------------------------------------------
+   Virtual Root HUB
+   ------------------------------------------------------------------------- */
+/* destination of request */
+#define RH_DEVICE              0x00
+#define RH_INTERFACE           0x01
+#define RH_ENDPOINT            0x02
+#define RH_OTHER               0x03
+
+#define RH_CLASS               0x20
+#define RH_VENDOR              0x40
+
+/* Requests: bRequest << 8 | bmRequestType */
+#define RH_GET_STATUS          0x0080
+#define RH_CLEAR_FEATURE       0x0100
+#define RH_SET_FEATURE         0x0300
+#define RH_SET_ADDRESS         0x0500
+#define RH_GET_DESCRIPTOR      0x0680
+#define RH_SET_DESCRIPTOR      0x0700
+#define RH_GET_CONFIGURATION   0x0880
+#define RH_SET_CONFIGURATION   0x0900
+#define RH_GET_STATE           0x0280
+#define RH_GET_INTERFACE       0x0A80
+#define RH_SET_INTERFACE       0x0B00
+#define RH_SYNC_FRAME          0x0C80
+/* Our Vendor Specific Request */
+#define RH_SET_EP              0x2000
+
+/* Hub port features */
+#define RH_PORT_CONNECTION     0x00
+#define RH_PORT_ENABLE         0x01
+#define RH_PORT_SUSPEND                0x02
+#define RH_PORT_OVER_CURRENT   0x03
+#define RH_PORT_RESET          0x04
+#define RH_PORT_POWER          0x08
+#define RH_PORT_LOW_SPEED      0x09
+#define RH_C_PORT_CONNECTION   0x10
+#define RH_C_PORT_ENABLE       0x11
+#define RH_C_PORT_SUSPEND      0x12
+#define RH_C_PORT_OVER_CURRENT 0x13
+#define RH_C_PORT_RESET                0x14
+
+/* Hub features */
+#define RH_C_HUB_LOCAL_POWER   0x00
+#define RH_C_HUB_OVER_CURRENT  0x01
+#define RH_DEVICE_REMOTE_WAKEUP        0x00
+#define RH_ENDPOINT_STALL      0x01
+
+/* Our Vendor Specific feature */
+#define RH_REMOVE_EP           0x00
+
+#define RH_ACK                 0x01
+#define RH_REQ_ERR             -1
+#define RH_NACK                        0x00
+
+#endif
+
diff --git a/linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/usbif.h b/linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/usbif.h
new file mode 100644 (file)
index 0000000..11cea15
--- /dev/null
@@ -0,0 +1,111 @@
+/******************************************************************************
+ * usbif.h
+ * 
+ * Unified block-device I/O interface for Xen guest OSes.
+ * 
+ * Copyright (c) 2003-2004, Keir Fraser
+ */
+
+#ifndef __SHARED_USBIF_H__
+#define __SHARED_USBIF_H__
+
+#define usbif_vdev_t   u16
+#define usbif_sector_t u64
+
+#define USBIF_OP_IO      0
+#define USBIF_OP_PROBE   1 /* Is there a device on this port? */
+#define USBIF_OP_RESET   2 /* Reset a virtual USB port.       */
+
+/* NB. Ring size must be small enough for sizeof(usbif_ring_t) <= PAGE_SIZE. */
+#define USBIF_RING_SIZE        64
+
+/* XXX this does not want to be here!  it really ought to be dynamic but it can
+ * live here for now */
+#define NUM_PORTS 1
+
+typedef struct {
+    unsigned long  id;           /*  0: private guest value, echoed in resp  */
+    u8             operation;    /*  4: USBIF_OP_???                         */
+    u8  __pad1;
+    usbif_vdev_t   port;         /* 6 : guest virtual USB port               */
+    unsigned long  devnum :7;    /* 8 : Device address, as seen by the guest.*/
+    unsigned long  endpoint :4;  /* Device endpoint.                         */
+    unsigned long  direction :1; /* Pipe direction.                          */
+    unsigned long  speed :1;     /* Pipe speed.                              */
+    unsigned long  pipe_type :2; /* Pipe type (iso, bulk, int, ctrl)         */
+    unsigned long  __pad2 :18;
+    unsigned long  transfer_buffer; /* 12: Machine address */
+    unsigned long  length;          /* 16: Buffer length */
+    unsigned long  transfer_flags;  /* 20: For now just pass Linux transfer
+                                     * flags - this may change. */
+    unsigned char setup[8];         /* 22 Embed setup packets directly. */
+    unsigned long  iso_schedule;    /* 30 Machine address of transfer sched (iso
+                                     * only) */
+    unsigned long num_iso;        /* 34 : length of iso schedule */
+    unsigned long timeout;        /* 38: timeout in ms */
+} PACKED usbif_request_t; /* 42 */
+/* Data we need to pass:
+ * - Transparently handle short packets or complain at us?
+ */
+
+typedef struct {
+    unsigned long   id;              /* 0: copied from request         */
+    u8              operation;       /* 4: copied from request         */
+    u8              data;            /* 5: Small chunk of in-band data */
+    s16             status;          /* 6: USBIF_RSP_???               */
+    unsigned long   transfer_mutex;  /* Used for cancelling requests atomically. */
+    unsigned long    length;          /* 8: How much data we really got */
+} PACKED usbif_response_t;
+
+#define USBIF_RSP_ERROR  -1 /* non-specific 'error' */
+#define USBIF_RSP_OKAY    0 /* non-specific 'okay'  */
+
+/*
+ * We use a special capitalised type name because it is _essential_ that all 
+ * arithmetic on indexes is done on an integer type of the correct size.
+ */
+typedef u32 USBIF_RING_IDX;
+
+/*
+ * Ring indexes are 'free running'. That is, they are not stored modulo the
+ * size of the ring buffer. The following macro converts a free-running counter
+ * into a value that can directly index a ring-buffer array.
+ */
+#define MASK_USBIF_IDX(_i) ((_i)&(USBIF_RING_SIZE-1))
+
+typedef struct {
+    USBIF_RING_IDX req_prod;  /*  0: Request producer. Updated by front-end. */
+    USBIF_RING_IDX resp_prod; /*  4: Response producer. Updated by back-end. */
+
+    union {                   /*  8 */
+        usbif_request_t  req;
+        usbif_response_t resp;
+    } PACKED ring[USBIF_RING_SIZE];
+} PACKED usbif_t;
+
+
+
+/*
+ * USBIF_OP_PROBE:
+ * The request format for a probe request is constrained as follows:
+ *  @operation   == USBIF_OP_PROBE
+ *  @nr_segments == size of probe buffer in pages
+ *  @device      == unused (zero)
+ *  @id          == any value (echoed in response message)
+ *  @sector_num  == unused (zero)
+ *  @frame_and_sects == list of page-sized buffers.
+ *                       (i.e., @first_sect == 0, @last_sect == 7).
+ * 
+ * The response is a list of vdisk_t elements copied into the out-of-band
+ * probe buffer. On success the response status field contains the number
+ * of vdisk_t elements.
+ */
+
+typedef struct {
+    unsigned long length; /* IN = expected, OUT = actual */
+    unsigned long buffer_offset;  /* IN offset in buffer specified in main
+                                     packet */
+    unsigned long status; /* OUT Status for this packet. */
+} usbif_iso_t;
+
+#endif /* __SHARED_USBIF_H__ */